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__) 245178573Sjb/* XXX */ 246178573Sjbprintf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); 247178479Sjb#elif defined(__sparc) 248178479Sjb /* 249178479Sjb * Add 4 bytes to hit the low half of this 64-bit 250178479Sjb * big-endian address. 251178479Sjb */ 252178479Sjb rel->r_offset = s->dofs_offset + 253178479Sjb dofr[j].dofr_offset + 4; 254178479Sjb rel->r_info = ELF32_R_INFO(count + dep->de_global, 255178479Sjb R_SPARC_32); 256178479Sjb#else 257178479Sjb#error unknown ISA 258178479Sjb#endif 259178479Sjb 260178479Sjb sym->st_name = base + dofr[j].dofr_name - 1; 261178479Sjb sym->st_value = 0; 262178479Sjb sym->st_size = 0; 263178479Sjb sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_FUNC); 264178479Sjb sym->st_other = 0; 265178479Sjb sym->st_shndx = SHN_UNDEF; 266178479Sjb 267178479Sjb rel++; 268178479Sjb sym++; 269178479Sjb count++; 270178479Sjb } 271178479Sjb } 272178479Sjb 273178479Sjb /* 274178479Sjb * Add a symbol for the DOF itself. We use a different symbol for 275178479Sjb * lazily and actively loaded DOF to make them easy to distinguish. 276178479Sjb */ 277178479Sjb sym->st_name = strtabsz; 278178479Sjb sym->st_value = 0; 279178479Sjb sym->st_size = dof->dofh_filesz; 280178479Sjb sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT); 281178479Sjb sym->st_other = 0; 282178479Sjb sym->st_shndx = ESHDR_DOF; 283178479Sjb sym++; 284178479Sjb 285178479Sjb if (dtp->dt_lazyload) { 286178479Sjb bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz, 287178479Sjb sizeof (DOFLAZYSTR)); 288178479Sjb strtabsz += sizeof (DOFLAZYSTR); 289178479Sjb } else { 290178479Sjb bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR)); 291178479Sjb strtabsz += sizeof (DOFSTR); 292178479Sjb } 293178479Sjb 294178479Sjb assert(count == dep->de_nrel); 295178479Sjb assert(strtabsz == dep->de_strlen); 296178479Sjb 297178479Sjb return (0); 298178479Sjb} 299178479Sjb 300178479Sjb 301178479Sjbtypedef struct dof_elf64 { 302178479Sjb uint32_t de_nrel; 303178479Sjb Elf64_Rela *de_rel; 304178479Sjb uint32_t de_nsym; 305178479Sjb Elf64_Sym *de_sym; 306178479Sjb 307178479Sjb uint32_t de_strlen; 308178479Sjb char *de_strtab; 309178479Sjb 310178479Sjb uint32_t de_global; 311178479Sjb} dof_elf64_t; 312178479Sjb 313178479Sjbstatic int 314178479Sjbprepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep) 315178479Sjb{ 316178479Sjb dof_sec_t *dofs, *s; 317178479Sjb dof_relohdr_t *dofrh; 318178479Sjb dof_relodesc_t *dofr; 319178479Sjb char *strtab; 320178479Sjb int i, j, nrel; 321178479Sjb size_t strtabsz = 1; 322178479Sjb uint32_t count = 0; 323178479Sjb size_t base; 324178479Sjb Elf64_Sym *sym; 325178479Sjb Elf64_Rela *rel; 326178479Sjb 327178479Sjb /*LINTED*/ 328178479Sjb dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff); 329178479Sjb 330178479Sjb /* 331178479Sjb * First compute the size of the string table and the number of 332178479Sjb * relocations present in the DOF. 333178479Sjb */ 334178479Sjb for (i = 0; i < dof->dofh_secnum; i++) { 335178479Sjb if (dofs[i].dofs_type != DOF_SECT_URELHDR) 336178479Sjb continue; 337178479Sjb 338178479Sjb /*LINTED*/ 339178479Sjb dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 340178479Sjb 341178479Sjb s = &dofs[dofrh->dofr_strtab]; 342178479Sjb strtab = (char *)dof + s->dofs_offset; 343178479Sjb assert(strtab[0] == '\0'); 344178479Sjb strtabsz += s->dofs_size - 1; 345178479Sjb 346178479Sjb s = &dofs[dofrh->dofr_relsec]; 347178479Sjb /*LINTED*/ 348178479Sjb dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 349178479Sjb count += s->dofs_size / s->dofs_entsize; 350178479Sjb } 351178479Sjb 352178479Sjb dep->de_strlen = strtabsz; 353178479Sjb dep->de_nrel = count; 354178479Sjb dep->de_nsym = count + 1; /* the first symbol is always null */ 355178479Sjb 356178479Sjb if (dtp->dt_lazyload) { 357178479Sjb dep->de_strlen += sizeof (DOFLAZYSTR); 358178479Sjb dep->de_nsym++; 359178479Sjb } else { 360178479Sjb dep->de_strlen += sizeof (DOFSTR); 361178479Sjb dep->de_nsym++; 362178479Sjb } 363178479Sjb 364178479Sjb if ((dep->de_rel = calloc(dep->de_nrel, 365178479Sjb sizeof (dep->de_rel[0]))) == NULL) { 366178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 367178479Sjb } 368178479Sjb 369178479Sjb if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf64_Sym))) == NULL) { 370178479Sjb free(dep->de_rel); 371178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 372178479Sjb } 373178479Sjb 374178479Sjb if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) { 375178479Sjb free(dep->de_rel); 376178479Sjb free(dep->de_sym); 377178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 378178479Sjb } 379178479Sjb 380178479Sjb count = 0; 381178479Sjb strtabsz = 1; 382178479Sjb dep->de_strtab[0] = '\0'; 383178479Sjb rel = dep->de_rel; 384178479Sjb sym = dep->de_sym; 385178479Sjb dep->de_global = 1; 386178479Sjb 387178479Sjb /* 388178479Sjb * The first symbol table entry must be zeroed and is always ignored. 389178479Sjb */ 390178479Sjb bzero(sym, sizeof (Elf64_Sym)); 391178479Sjb sym++; 392178479Sjb 393178479Sjb /* 394178479Sjb * Take a second pass through the DOF sections filling in the 395178479Sjb * memory we allocated. 396178479Sjb */ 397178479Sjb for (i = 0; i < dof->dofh_secnum; i++) { 398178479Sjb if (dofs[i].dofs_type != DOF_SECT_URELHDR) 399178479Sjb continue; 400178479Sjb 401178479Sjb /*LINTED*/ 402178479Sjb dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 403178479Sjb 404178479Sjb s = &dofs[dofrh->dofr_strtab]; 405178479Sjb strtab = (char *)dof + s->dofs_offset; 406178479Sjb bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size); 407178479Sjb base = strtabsz; 408178479Sjb strtabsz += s->dofs_size - 1; 409178479Sjb 410178479Sjb s = &dofs[dofrh->dofr_relsec]; 411178479Sjb /*LINTED*/ 412178479Sjb dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 413178479Sjb nrel = s->dofs_size / s->dofs_entsize; 414178479Sjb 415178479Sjb s = &dofs[dofrh->dofr_tgtsec]; 416178479Sjb 417178479Sjb for (j = 0; j < nrel; j++) { 418178573Sjb#ifdef DOODAD 419178573Sjb#if defined(__arm__) 420178573Sjb/* XXX */ 421178573Sjb#elif defined(__ia64__) 422178573Sjb/* XXX */ 423178573Sjb#elif defined(__mips__) 424178573Sjb/* XXX */ 425178573Sjb#elif defined(__powerpc__) 426178573Sjb/* XXX */ 427178573Sjb#elif defined(__i386) || defined(__amd64) 428178479Sjb rel->r_offset = s->dofs_offset + 429178479Sjb dofr[j].dofr_offset; 430178479Sjb rel->r_info = ELF64_R_INFO(count + dep->de_global, 431178479Sjb R_AMD64_64); 432178479Sjb#elif defined(__sparc) 433178479Sjb rel->r_offset = s->dofs_offset + 434178479Sjb dofr[j].dofr_offset; 435178479Sjb rel->r_info = ELF64_R_INFO(count + dep->de_global, 436178479Sjb R_SPARC_64); 437178479Sjb#else 438178479Sjb#error unknown ISA 439178479Sjb#endif 440178573Sjb#endif 441178479Sjb 442178479Sjb sym->st_name = base + dofr[j].dofr_name - 1; 443178479Sjb sym->st_value = 0; 444178479Sjb sym->st_size = 0; 445178479Sjb sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC); 446178479Sjb sym->st_other = 0; 447178479Sjb sym->st_shndx = SHN_UNDEF; 448178479Sjb 449178479Sjb rel++; 450178479Sjb sym++; 451178479Sjb count++; 452178479Sjb } 453178479Sjb } 454178479Sjb 455178479Sjb /* 456178479Sjb * Add a symbol for the DOF itself. We use a different symbol for 457178479Sjb * lazily and actively loaded DOF to make them easy to distinguish. 458178479Sjb */ 459178479Sjb sym->st_name = strtabsz; 460178479Sjb sym->st_value = 0; 461178479Sjb sym->st_size = dof->dofh_filesz; 462178479Sjb sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_OBJECT); 463178479Sjb sym->st_other = 0; 464178479Sjb sym->st_shndx = ESHDR_DOF; 465178479Sjb sym++; 466178479Sjb 467178479Sjb if (dtp->dt_lazyload) { 468178479Sjb bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz, 469178479Sjb sizeof (DOFLAZYSTR)); 470178479Sjb strtabsz += sizeof (DOFLAZYSTR); 471178479Sjb } else { 472178479Sjb bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR)); 473178479Sjb strtabsz += sizeof (DOFSTR); 474178479Sjb } 475178479Sjb 476178479Sjb assert(count == dep->de_nrel); 477178479Sjb assert(strtabsz == dep->de_strlen); 478178479Sjb 479178479Sjb return (0); 480178479Sjb} 481178479Sjb 482178479Sjb/* 483178479Sjb * Write out an ELF32 file prologue consisting of a header, section headers, 484178479Sjb * and a section header string table. The DOF data will follow this prologue 485178479Sjb * and complete the contents of the given ELF file. 486178479Sjb */ 487178479Sjbstatic int 488178479Sjbdump_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) 489178479Sjb{ 490178479Sjb struct { 491178479Sjb Elf32_Ehdr ehdr; 492178479Sjb Elf32_Shdr shdr[ESHDR_NUM]; 493178479Sjb } elf_file; 494178479Sjb 495178479Sjb Elf32_Shdr *shp; 496178479Sjb Elf32_Off off; 497178479Sjb dof_elf32_t de; 498178479Sjb int ret = 0; 499178479Sjb uint_t nshdr; 500178479Sjb 501178479Sjb if (prepare_elf32(dtp, dof, &de) != 0) 502178479Sjb return (-1); /* errno is set for us */ 503178479Sjb 504178479Sjb /* 505178479Sjb * If there are no relocations, we only need enough sections for 506178479Sjb * the shstrtab and the DOF. 507178479Sjb */ 508178479Sjb nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; 509178479Sjb 510178479Sjb bzero(&elf_file, sizeof (elf_file)); 511178479Sjb 512178479Sjb elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; 513178479Sjb elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; 514178479Sjb elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; 515178479Sjb elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; 516178479Sjb elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; 517178479Sjb elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS32; 518178573Sjb#if BYTE_ORDER == _BIG_ENDIAN 519178479Sjb elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; 520178573Sjb#else 521178479Sjb elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; 522178479Sjb#endif 523178573Sjb#if defined(__FreeBSD__) 524178573Sjb elf_file.ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; 525178573Sjb#endif 526178479Sjb elf_file.ehdr.e_type = ET_REL; 527178573Sjb#if defined(__arm__) 528178573Sjb elf_file.ehdr.e_machine = EM_ARM; 529178573Sjb#elif defined(__ia64__) 530178573Sjb elf_file.ehdr.e_machine = EM_IA_64; 531178573Sjb#elif defined(__mips__) 532178573Sjb elf_file.ehdr.e_machine = EM_MIPS; 533178573Sjb#elif defined(__powerpc__) 534178573Sjb elf_file.ehdr.e_machine = EM_PPC; 535178573Sjb#elif defined(__sparc) 536178479Sjb elf_file.ehdr.e_machine = EM_SPARC; 537178479Sjb#elif defined(__i386) || defined(__amd64) 538178479Sjb elf_file.ehdr.e_machine = EM_386; 539178479Sjb#endif 540178479Sjb elf_file.ehdr.e_version = EV_CURRENT; 541178479Sjb elf_file.ehdr.e_shoff = sizeof (Elf32_Ehdr); 542178479Sjb elf_file.ehdr.e_ehsize = sizeof (Elf32_Ehdr); 543178479Sjb elf_file.ehdr.e_phentsize = sizeof (Elf32_Phdr); 544178479Sjb elf_file.ehdr.e_shentsize = sizeof (Elf32_Shdr); 545178479Sjb elf_file.ehdr.e_shnum = nshdr; 546178479Sjb elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; 547178479Sjb off = sizeof (elf_file) + nshdr * sizeof (Elf32_Shdr); 548178479Sjb 549178479Sjb shp = &elf_file.shdr[ESHDR_SHSTRTAB]; 550178479Sjb shp->sh_name = 1; /* DTRACE_SHSTRTAB32[1] = ".shstrtab" */ 551178479Sjb shp->sh_type = SHT_STRTAB; 552178479Sjb shp->sh_offset = off; 553178479Sjb shp->sh_size = sizeof (DTRACE_SHSTRTAB32); 554178479Sjb shp->sh_addralign = sizeof (char); 555178479Sjb off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 556178479Sjb 557178479Sjb shp = &elf_file.shdr[ESHDR_DOF]; 558178479Sjb shp->sh_name = 11; /* DTRACE_SHSTRTAB32[11] = ".SUNW_dof" */ 559178479Sjb shp->sh_flags = SHF_ALLOC; 560178479Sjb shp->sh_type = SHT_SUNW_dof; 561178479Sjb shp->sh_offset = off; 562178479Sjb shp->sh_size = dof->dofh_filesz; 563178479Sjb shp->sh_addralign = 8; 564178479Sjb off = shp->sh_offset + shp->sh_size; 565178479Sjb 566178479Sjb shp = &elf_file.shdr[ESHDR_STRTAB]; 567178479Sjb shp->sh_name = 21; /* DTRACE_SHSTRTAB32[21] = ".strtab" */ 568178479Sjb shp->sh_flags = SHF_ALLOC; 569178479Sjb shp->sh_type = SHT_STRTAB; 570178479Sjb shp->sh_offset = off; 571178479Sjb shp->sh_size = de.de_strlen; 572178479Sjb shp->sh_addralign = sizeof (char); 573178479Sjb off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4); 574178479Sjb 575178479Sjb shp = &elf_file.shdr[ESHDR_SYMTAB]; 576178479Sjb shp->sh_name = 29; /* DTRACE_SHSTRTAB32[29] = ".symtab" */ 577178479Sjb shp->sh_flags = SHF_ALLOC; 578178479Sjb shp->sh_type = SHT_SYMTAB; 579178479Sjb shp->sh_entsize = sizeof (Elf32_Sym); 580178479Sjb shp->sh_link = ESHDR_STRTAB; 581178479Sjb shp->sh_offset = off; 582178479Sjb shp->sh_info = de.de_global; 583178479Sjb shp->sh_size = de.de_nsym * sizeof (Elf32_Sym); 584178479Sjb shp->sh_addralign = 4; 585178479Sjb off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4); 586178479Sjb 587178479Sjb if (de.de_nrel == 0) { 588178479Sjb if (dt_write(dtp, fd, &elf_file, 589178479Sjb sizeof (elf_file)) != sizeof (elf_file) || 590178479Sjb PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || 591178479Sjb PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 592178479Sjb PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 593178479Sjb PWRITE_SCN(ESHDR_DOF, dof)) { 594178479Sjb ret = dt_set_errno(dtp, errno); 595178479Sjb } 596178479Sjb } else { 597178479Sjb shp = &elf_file.shdr[ESHDR_REL]; 598178479Sjb shp->sh_name = 37; /* DTRACE_SHSTRTAB32[37] = ".rel.SUNW_dof" */ 599178479Sjb shp->sh_flags = SHF_ALLOC; 600178479Sjb#ifdef __sparc 601178479Sjb shp->sh_type = SHT_RELA; 602178479Sjb#else 603178479Sjb shp->sh_type = SHT_REL; 604178479Sjb#endif 605178479Sjb shp->sh_entsize = sizeof (de.de_rel[0]); 606178479Sjb shp->sh_link = ESHDR_SYMTAB; 607178479Sjb shp->sh_info = ESHDR_DOF; 608178479Sjb shp->sh_offset = off; 609178479Sjb shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]); 610178479Sjb shp->sh_addralign = 4; 611178479Sjb 612178479Sjb if (dt_write(dtp, fd, &elf_file, 613178479Sjb sizeof (elf_file)) != sizeof (elf_file) || 614178479Sjb PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || 615178479Sjb PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 616178479Sjb PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 617178479Sjb PWRITE_SCN(ESHDR_REL, de.de_rel) || 618178479Sjb PWRITE_SCN(ESHDR_DOF, dof)) { 619178479Sjb ret = dt_set_errno(dtp, errno); 620178479Sjb } 621178479Sjb } 622178479Sjb 623178479Sjb free(de.de_strtab); 624178479Sjb free(de.de_sym); 625178479Sjb free(de.de_rel); 626178479Sjb 627178479Sjb return (ret); 628178479Sjb} 629178479Sjb 630178479Sjb/* 631178479Sjb * Write out an ELF64 file prologue consisting of a header, section headers, 632178479Sjb * and a section header string table. The DOF data will follow this prologue 633178479Sjb * and complete the contents of the given ELF file. 634178479Sjb */ 635178479Sjbstatic int 636178479Sjbdump_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) 637178479Sjb{ 638178479Sjb struct { 639178479Sjb Elf64_Ehdr ehdr; 640178479Sjb Elf64_Shdr shdr[ESHDR_NUM]; 641178479Sjb } elf_file; 642178479Sjb 643178479Sjb Elf64_Shdr *shp; 644178479Sjb Elf64_Off off; 645178479Sjb dof_elf64_t de; 646178479Sjb int ret = 0; 647178479Sjb uint_t nshdr; 648178479Sjb 649178479Sjb if (prepare_elf64(dtp, dof, &de) != 0) 650178479Sjb return (-1); /* errno is set for us */ 651178479Sjb 652178479Sjb /* 653178479Sjb * If there are no relocations, we only need enough sections for 654178479Sjb * the shstrtab and the DOF. 655178479Sjb */ 656178479Sjb nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; 657178479Sjb 658178479Sjb bzero(&elf_file, sizeof (elf_file)); 659178479Sjb 660178479Sjb elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; 661178479Sjb elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; 662178479Sjb elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; 663178479Sjb elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; 664178479Sjb elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; 665178479Sjb elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS64; 666178573Sjb#if BYTE_ORDER == _BIG_ENDIAN 667178479Sjb elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; 668178573Sjb#else 669178479Sjb elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; 670178479Sjb#endif 671178573Sjb#if defined(__FreeBSD__) 672178573Sjb elf_file.ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; 673178573Sjb#endif 674178479Sjb elf_file.ehdr.e_type = ET_REL; 675178573Sjb#if defined(__arm__) 676178573Sjb elf_file.ehdr.e_machine = EM_ARM; 677178573Sjb#elif defined(__ia64__) 678178573Sjb elf_file.ehdr.e_machine = EM_IA_64; 679178573Sjb#elif defined(__mips__) 680178573Sjb elf_file.ehdr.e_machine = EM_MIPS; 681178573Sjb#elif defined(__powerpc__) 682178573Sjb elf_file.ehdr.e_machine = EM_PPC; 683178573Sjb#elif defined(__sparc) 684178479Sjb elf_file.ehdr.e_machine = EM_SPARCV9; 685178479Sjb#elif defined(__i386) || defined(__amd64) 686178479Sjb elf_file.ehdr.e_machine = EM_AMD64; 687178479Sjb#endif 688178479Sjb elf_file.ehdr.e_version = EV_CURRENT; 689178479Sjb elf_file.ehdr.e_shoff = sizeof (Elf64_Ehdr); 690178479Sjb elf_file.ehdr.e_ehsize = sizeof (Elf64_Ehdr); 691178479Sjb elf_file.ehdr.e_phentsize = sizeof (Elf64_Phdr); 692178479Sjb elf_file.ehdr.e_shentsize = sizeof (Elf64_Shdr); 693178479Sjb elf_file.ehdr.e_shnum = nshdr; 694178479Sjb elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; 695178479Sjb off = sizeof (elf_file) + nshdr * sizeof (Elf64_Shdr); 696178479Sjb 697178479Sjb shp = &elf_file.shdr[ESHDR_SHSTRTAB]; 698178479Sjb shp->sh_name = 1; /* DTRACE_SHSTRTAB64[1] = ".shstrtab" */ 699178479Sjb shp->sh_type = SHT_STRTAB; 700178479Sjb shp->sh_offset = off; 701178479Sjb shp->sh_size = sizeof (DTRACE_SHSTRTAB64); 702178479Sjb shp->sh_addralign = sizeof (char); 703178479Sjb off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 704178479Sjb 705178479Sjb shp = &elf_file.shdr[ESHDR_DOF]; 706178479Sjb shp->sh_name = 11; /* DTRACE_SHSTRTAB64[11] = ".SUNW_dof" */ 707178479Sjb shp->sh_flags = SHF_ALLOC; 708178479Sjb shp->sh_type = SHT_SUNW_dof; 709178479Sjb shp->sh_offset = off; 710178479Sjb shp->sh_size = dof->dofh_filesz; 711178479Sjb shp->sh_addralign = 8; 712178479Sjb off = shp->sh_offset + shp->sh_size; 713178479Sjb 714178479Sjb shp = &elf_file.shdr[ESHDR_STRTAB]; 715178479Sjb shp->sh_name = 21; /* DTRACE_SHSTRTAB64[21] = ".strtab" */ 716178479Sjb shp->sh_flags = SHF_ALLOC; 717178479Sjb shp->sh_type = SHT_STRTAB; 718178479Sjb shp->sh_offset = off; 719178479Sjb shp->sh_size = de.de_strlen; 720178479Sjb shp->sh_addralign = sizeof (char); 721178479Sjb off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 722178479Sjb 723178479Sjb shp = &elf_file.shdr[ESHDR_SYMTAB]; 724178479Sjb shp->sh_name = 29; /* DTRACE_SHSTRTAB64[29] = ".symtab" */ 725178479Sjb shp->sh_flags = SHF_ALLOC; 726178479Sjb shp->sh_type = SHT_SYMTAB; 727178479Sjb shp->sh_entsize = sizeof (Elf64_Sym); 728178479Sjb shp->sh_link = ESHDR_STRTAB; 729178479Sjb shp->sh_offset = off; 730178479Sjb shp->sh_info = de.de_global; 731178479Sjb shp->sh_size = de.de_nsym * sizeof (Elf64_Sym); 732178479Sjb shp->sh_addralign = 8; 733178479Sjb off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 734178479Sjb 735178479Sjb if (de.de_nrel == 0) { 736178479Sjb if (dt_write(dtp, fd, &elf_file, 737178479Sjb sizeof (elf_file)) != sizeof (elf_file) || 738178479Sjb PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || 739178479Sjb PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 740178479Sjb PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 741178479Sjb PWRITE_SCN(ESHDR_DOF, dof)) { 742178479Sjb ret = dt_set_errno(dtp, errno); 743178479Sjb } 744178479Sjb } else { 745178479Sjb shp = &elf_file.shdr[ESHDR_REL]; 746178479Sjb shp->sh_name = 37; /* DTRACE_SHSTRTAB64[37] = ".rel.SUNW_dof" */ 747178479Sjb shp->sh_flags = SHF_ALLOC; 748178479Sjb shp->sh_type = SHT_RELA; 749178479Sjb shp->sh_entsize = sizeof (de.de_rel[0]); 750178479Sjb shp->sh_link = ESHDR_SYMTAB; 751178479Sjb shp->sh_info = ESHDR_DOF; 752178479Sjb shp->sh_offset = off; 753178479Sjb shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]); 754178479Sjb shp->sh_addralign = 8; 755178479Sjb 756178479Sjb if (dt_write(dtp, fd, &elf_file, 757178479Sjb sizeof (elf_file)) != sizeof (elf_file) || 758178479Sjb PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || 759178479Sjb PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 760178479Sjb PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 761178479Sjb PWRITE_SCN(ESHDR_REL, de.de_rel) || 762178479Sjb PWRITE_SCN(ESHDR_DOF, dof)) { 763178479Sjb ret = dt_set_errno(dtp, errno); 764178479Sjb } 765178479Sjb } 766178479Sjb 767178479Sjb free(de.de_strtab); 768178479Sjb free(de.de_sym); 769178479Sjb free(de.de_rel); 770178479Sjb 771178479Sjb return (ret); 772178479Sjb} 773178479Sjb 774178479Sjbstatic int 775178479Sjbdt_symtab_lookup(Elf_Data *data_sym, int nsym, uintptr_t addr, uint_t shn, 776178479Sjb GElf_Sym *sym) 777178479Sjb{ 778178479Sjb int i, ret = -1; 779178479Sjb GElf_Sym s; 780178479Sjb 781178479Sjb for (i = 0; i < nsym && gelf_getsym(data_sym, i, sym) != NULL; i++) { 782178479Sjb if (GELF_ST_TYPE(sym->st_info) == STT_FUNC && 783178479Sjb shn == sym->st_shndx && 784178479Sjb sym->st_value <= addr && 785178479Sjb addr < sym->st_value + sym->st_size) { 786178479Sjb if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL) 787178479Sjb return (0); 788178479Sjb 789178479Sjb ret = 0; 790178479Sjb s = *sym; 791178479Sjb } 792178479Sjb } 793178479Sjb 794178479Sjb if (ret == 0) 795178479Sjb *sym = s; 796178479Sjb return (ret); 797178479Sjb} 798178479Sjb 799178573Sjb#if defined(__arm__) 800178573Sjb/* XXX */ 801178573Sjbstatic int 802178573Sjbdt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, 803178573Sjb uint32_t *off) 804178573Sjb{ 805178573Sjbprintf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); 806178573Sjb return (0); 807178573Sjb} 808178573Sjb#elif defined(__ia64__) 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(__mips__) 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(__powerpc__) 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} 835178479Sjb 836178573Sjb#elif defined(__sparc) 837178573Sjb 838178479Sjb#define DT_OP_RET 0x81c7e008 839178479Sjb#define DT_OP_NOP 0x01000000 840178479Sjb#define DT_OP_CALL 0x40000000 841178479Sjb#define DT_OP_CLR_O0 0x90102000 842178479Sjb 843178479Sjb#define DT_IS_MOV_O7(inst) (((inst) & 0xffffe000) == 0x9e100000) 844178479Sjb#define DT_IS_RESTORE(inst) (((inst) & 0xc1f80000) == 0x81e80000) 845178479Sjb#define DT_IS_RETL(inst) (((inst) & 0xfff83fff) == 0x81c02008) 846178479Sjb 847178479Sjb#define DT_RS2(inst) ((inst) & 0x1f) 848178479Sjb#define DT_MAKE_RETL(reg) (0x81c02008 | ((reg) << 14)) 849178479Sjb 850178479Sjb/*ARGSUSED*/ 851178479Sjbstatic int 852178479Sjbdt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, 853178479Sjb uint32_t *off) 854178479Sjb{ 855178479Sjb uint32_t *ip; 856178479Sjb 857178479Sjb if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0) 858178479Sjb return (-1); 859178479Sjb 860178479Sjb /*LINTED*/ 861178479Sjb ip = (uint32_t *)(p + rela->r_offset); 862178479Sjb 863178479Sjb /* 864178479Sjb * We only know about some specific relocation types. 865178479Sjb */ 866178479Sjb if (GELF_R_TYPE(rela->r_info) != R_SPARC_WDISP30 && 867178479Sjb GELF_R_TYPE(rela->r_info) != R_SPARC_WPLT30) 868178479Sjb return (-1); 869178479Sjb 870178479Sjb /* 871178479Sjb * We may have already processed this object file in an earlier linker 872178479Sjb * invocation. Check to see if the present instruction sequence matches 873184696Srodrigc * the one we would install below. 874178479Sjb */ 875178479Sjb if (isenabled) { 876184696Srodrigc if (ip[0] == DT_OP_NOP) { 877184696Srodrigc (*off) += sizeof (ip[0]); 878178479Sjb return (0); 879184696Srodrigc } 880178479Sjb } else { 881178479Sjb if (DT_IS_RESTORE(ip[1])) { 882184696Srodrigc if (ip[0] == DT_OP_RET) { 883184696Srodrigc (*off) += sizeof (ip[0]); 884178479Sjb return (0); 885184696Srodrigc } 886178479Sjb } else if (DT_IS_MOV_O7(ip[1])) { 887178479Sjb if (DT_IS_RETL(ip[0])) 888178479Sjb return (0); 889178479Sjb } else { 890178479Sjb if (ip[0] == DT_OP_NOP) { 891178479Sjb (*off) += sizeof (ip[0]); 892178479Sjb return (0); 893178479Sjb } 894178479Sjb } 895178479Sjb } 896178479Sjb 897178479Sjb /* 898178479Sjb * We only expect call instructions with a displacement of 0. 899178479Sjb */ 900178479Sjb if (ip[0] != DT_OP_CALL) { 901178479Sjb dt_dprintf("found %x instead of a call instruction at %llx\n", 902178479Sjb ip[0], (u_longlong_t)rela->r_offset); 903178479Sjb return (-1); 904178479Sjb } 905178479Sjb 906178479Sjb if (isenabled) { 907178479Sjb /* 908178479Sjb * It would necessarily indicate incorrect usage if an is- 909178479Sjb * enabled probe were tail-called so flag that as an error. 910178479Sjb * It's also potentially (very) tricky to handle gracefully, 911178479Sjb * but could be done if this were a desired use scenario. 912178479Sjb */ 913178479Sjb if (DT_IS_RESTORE(ip[1]) || DT_IS_MOV_O7(ip[1])) { 914178479Sjb dt_dprintf("tail call to is-enabled probe at %llx\n", 915178479Sjb (u_longlong_t)rela->r_offset); 916178479Sjb return (-1); 917178479Sjb } 918178479Sjb 919184696Srodrigc 920184696Srodrigc /* 921184696Srodrigc * On SPARC, we take advantage of the fact that the first 922184696Srodrigc * argument shares the same register as for the return value. 923184696Srodrigc * The macro handles the work of zeroing that register so we 924184696Srodrigc * don't need to do anything special here. We instrument the 925184696Srodrigc * instruction in the delay slot as we'll need to modify the 926184696Srodrigc * return register after that instruction has been emulated. 927184696Srodrigc */ 928184696Srodrigc ip[0] = DT_OP_NOP; 929184696Srodrigc (*off) += sizeof (ip[0]); 930178479Sjb } else { 931178479Sjb /* 932178479Sjb * If the call is followed by a restore, it's a tail call so 933178479Sjb * change the call to a ret. If the call if followed by a mov 934178479Sjb * of a register into %o7, it's a tail call in leaf context 935178479Sjb * so change the call to a retl-like instruction that returns 936178479Sjb * to that register value + 8 (rather than the typical %o7 + 937178479Sjb * 8); the delay slot instruction is left, but should have no 938184696Srodrigc * effect. Otherwise we change the call to be a nop. We 939184696Srodrigc * identify the subsequent instruction as the probe point in 940184696Srodrigc * all but the leaf tail-call case to ensure that arguments to 941184696Srodrigc * the probe are complete and consistent. An astute, though 942184696Srodrigc * largely hypothetical, observer would note that there is the 943184696Srodrigc * possibility of a false-positive probe firing if the function 944184696Srodrigc * contained a branch to the instruction in the delay slot of 945184696Srodrigc * the call. Fixing this would require significant in-kernel 946184696Srodrigc * modifications, and isn't worth doing until we see it in the 947184696Srodrigc * wild. 948178479Sjb */ 949178479Sjb if (DT_IS_RESTORE(ip[1])) { 950178479Sjb ip[0] = DT_OP_RET; 951178479Sjb (*off) += sizeof (ip[0]); 952178479Sjb } else if (DT_IS_MOV_O7(ip[1])) { 953178479Sjb ip[0] = DT_MAKE_RETL(DT_RS2(ip[1])); 954178479Sjb } else { 955178479Sjb ip[0] = DT_OP_NOP; 956178479Sjb (*off) += sizeof (ip[0]); 957178479Sjb } 958178479Sjb } 959178479Sjb 960178479Sjb return (0); 961178479Sjb} 962178479Sjb 963178479Sjb#elif defined(__i386) || defined(__amd64) 964178479Sjb 965178479Sjb#define DT_OP_NOP 0x90 966178573Sjb#define DT_OP_RET 0xc3 967178479Sjb#define DT_OP_CALL 0xe8 968178573Sjb#define DT_OP_JMP32 0xe9 969178479Sjb#define DT_OP_REX_RAX 0x48 970178479Sjb#define DT_OP_XOR_EAX_0 0x33 971178479Sjb#define DT_OP_XOR_EAX_1 0xc0 972178479Sjb 973178479Sjbstatic int 974178479Sjbdt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, 975178479Sjb uint32_t *off) 976178479Sjb{ 977178479Sjb uint8_t *ip = (uint8_t *)(p + rela->r_offset - 1); 978178573Sjb uint8_t ret; 979178479Sjb 980178479Sjb /* 981178479Sjb * On x86, the first byte of the instruction is the call opcode and 982178479Sjb * the next four bytes are the 32-bit address; the relocation is for 983178479Sjb * the address operand. We back up the offset to the first byte of 984178479Sjb * the instruction. For is-enabled probes, we later advance the offset 985178479Sjb * so that it hits the first nop in the instruction sequence. 986178479Sjb */ 987178479Sjb (*off) -= 1; 988178479Sjb 989178479Sjb /* 990178479Sjb * We only know about some specific relocation types. Luckily 991178479Sjb * these types have the same values on both 32-bit and 64-bit 992178479Sjb * x86 architectures. 993178479Sjb */ 994178479Sjb if (GELF_R_TYPE(rela->r_info) != R_386_PC32 && 995178479Sjb GELF_R_TYPE(rela->r_info) != R_386_PLT32) 996178479Sjb return (-1); 997178479Sjb 998178479Sjb /* 999178479Sjb * We may have already processed this object file in an earlier linker 1000178479Sjb * invocation. Check to see if the present instruction sequence matches 1001178479Sjb * the one we would install. For is-enabled probes, we advance the 1002178573Sjb * offset to the first nop instruction in the sequence to match the 1003178573Sjb * text modification code below. 1004178479Sjb */ 1005178479Sjb if (!isenabled) { 1006178573Sjb if ((ip[0] == DT_OP_NOP || ip[0] == DT_OP_RET) && 1007178573Sjb ip[1] == DT_OP_NOP && ip[2] == DT_OP_NOP && 1008178573Sjb ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) 1009178479Sjb return (0); 1010178479Sjb } else if (dtp->dt_oflags & DTRACE_O_LP64) { 1011178479Sjb if (ip[0] == DT_OP_REX_RAX && 1012178479Sjb ip[1] == DT_OP_XOR_EAX_0 && ip[2] == DT_OP_XOR_EAX_1 && 1013178573Sjb (ip[3] == DT_OP_NOP || ip[3] == DT_OP_RET) && 1014178573Sjb ip[4] == DT_OP_NOP) { 1015178479Sjb (*off) += 3; 1016178479Sjb return (0); 1017178479Sjb } 1018178479Sjb } else { 1019178479Sjb if (ip[0] == DT_OP_XOR_EAX_0 && ip[1] == DT_OP_XOR_EAX_1 && 1020178573Sjb (ip[2] == DT_OP_NOP || ip[2] == DT_OP_RET) && 1021178573Sjb ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) { 1022178479Sjb (*off) += 2; 1023178479Sjb return (0); 1024178479Sjb } 1025178479Sjb } 1026178479Sjb 1027178479Sjb /* 1028178573Sjb * We expect either a call instrution with a 32-bit displacement or a 1029178573Sjb * jmp instruction with a 32-bit displacement acting as a tail-call. 1030178479Sjb */ 1031178573Sjb if (ip[0] != DT_OP_CALL && ip[0] != DT_OP_JMP32) { 1032178573Sjb dt_dprintf("found %x instead of a call or jmp instruction at " 1033178573Sjb "%llx\n", ip[0], (u_longlong_t)rela->r_offset); 1034178479Sjb return (-1); 1035178479Sjb } 1036178479Sjb 1037178573Sjb ret = (ip[0] == DT_OP_JMP32) ? DT_OP_RET : DT_OP_NOP; 1038178573Sjb 1039178479Sjb /* 1040178479Sjb * Establish the instruction sequence -- all nops for probes, and an 1041178479Sjb * instruction to clear the return value register (%eax/%rax) followed 1042178479Sjb * by nops for is-enabled probes. For is-enabled probes, we advance 1043178479Sjb * the offset to the first nop. This isn't stricly necessary but makes 1044178479Sjb * for more readable disassembly when the probe is enabled. 1045178479Sjb */ 1046178479Sjb if (!isenabled) { 1047178573Sjb ip[0] = ret; 1048178479Sjb ip[1] = DT_OP_NOP; 1049178479Sjb ip[2] = DT_OP_NOP; 1050178479Sjb ip[3] = DT_OP_NOP; 1051178479Sjb ip[4] = DT_OP_NOP; 1052178479Sjb } else if (dtp->dt_oflags & DTRACE_O_LP64) { 1053178479Sjb ip[0] = DT_OP_REX_RAX; 1054178479Sjb ip[1] = DT_OP_XOR_EAX_0; 1055178479Sjb ip[2] = DT_OP_XOR_EAX_1; 1056178573Sjb ip[3] = ret; 1057178479Sjb ip[4] = DT_OP_NOP; 1058178479Sjb (*off) += 3; 1059178479Sjb } else { 1060178479Sjb ip[0] = DT_OP_XOR_EAX_0; 1061178479Sjb ip[1] = DT_OP_XOR_EAX_1; 1062178573Sjb ip[2] = ret; 1063178479Sjb ip[3] = DT_OP_NOP; 1064178479Sjb ip[4] = DT_OP_NOP; 1065178479Sjb (*off) += 2; 1066178479Sjb } 1067178479Sjb 1068178479Sjb return (0); 1069178479Sjb} 1070178479Sjb 1071178479Sjb#else 1072178479Sjb#error unknown ISA 1073178479Sjb#endif 1074178479Sjb 1075178479Sjb/*PRINTFLIKE5*/ 1076178479Sjbstatic int 1077178479Sjbdt_link_error(dtrace_hdl_t *dtp, Elf *elf, int fd, dt_link_pair_t *bufs, 1078178479Sjb const char *format, ...) 1079178479Sjb{ 1080178479Sjb va_list ap; 1081178479Sjb dt_link_pair_t *pair; 1082178479Sjb 1083178479Sjb va_start(ap, format); 1084178479Sjb dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap); 1085178479Sjb va_end(ap); 1086178479Sjb 1087178479Sjb if (elf != NULL) 1088178479Sjb (void) elf_end(elf); 1089178479Sjb 1090178479Sjb if (fd >= 0) 1091178479Sjb (void) close(fd); 1092178479Sjb 1093178479Sjb while ((pair = bufs) != NULL) { 1094178479Sjb bufs = pair->dlp_next; 1095178479Sjb dt_free(dtp, pair->dlp_str); 1096178479Sjb dt_free(dtp, pair->dlp_sym); 1097178479Sjb dt_free(dtp, pair); 1098178479Sjb } 1099178479Sjb 1100178479Sjb return (dt_set_errno(dtp, EDT_COMPILER)); 1101178479Sjb} 1102178479Sjb 1103178479Sjbstatic int 1104178479Sjbprocess_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp) 1105178479Sjb{ 1106178479Sjb static const char dt_prefix[] = "__dtrace"; 1107178479Sjb static const char dt_enabled[] = "enabled"; 1108178479Sjb static const char dt_symprefix[] = "$dtrace"; 1109229091Sdim static const char dt_symfmt[] = "%s%ld.%s"; 1110178479Sjb int fd, i, ndx, eprobe, mod = 0; 1111178479Sjb Elf *elf = NULL; 1112178479Sjb GElf_Ehdr ehdr; 1113178479Sjb Elf_Scn *scn_rel, *scn_sym, *scn_str, *scn_tgt; 1114178479Sjb Elf_Data *data_rel, *data_sym, *data_str, *data_tgt; 1115178479Sjb GElf_Shdr shdr_rel, shdr_sym, shdr_str, shdr_tgt; 1116178479Sjb GElf_Sym rsym, fsym, dsym; 1117178479Sjb GElf_Rela rela; 1118178479Sjb char *s, *p, *r; 1119178479Sjb char pname[DTRACE_PROVNAMELEN]; 1120178479Sjb dt_provider_t *pvp; 1121178479Sjb dt_probe_t *prp; 1122178479Sjb uint32_t off, eclass, emachine1, emachine2; 1123178479Sjb size_t symsize, nsym, isym, istr, len; 1124178479Sjb key_t objkey; 1125178479Sjb dt_link_pair_t *pair, *bufs = NULL; 1126178479Sjb dt_strtab_t *strtab; 1127178479Sjb 1128178479Sjb if ((fd = open64(obj, O_RDWR)) == -1) { 1129178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1130178479Sjb "failed to open %s: %s", obj, strerror(errno))); 1131178479Sjb } 1132178479Sjb 1133178479Sjb if ((elf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL) { 1134178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1135178479Sjb "failed to process %s: %s", obj, elf_errmsg(elf_errno()))); 1136178479Sjb } 1137178479Sjb 1138178479Sjb switch (elf_kind(elf)) { 1139178479Sjb case ELF_K_ELF: 1140178479Sjb break; 1141178479Sjb case ELF_K_AR: 1142178479Sjb return (dt_link_error(dtp, elf, fd, bufs, "archives are not " 1143178479Sjb "permitted; use the contents of the archive instead: %s", 1144178479Sjb obj)); 1145178479Sjb default: 1146178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1147178479Sjb "invalid file type: %s", obj)); 1148178479Sjb } 1149178479Sjb 1150178479Sjb if (gelf_getehdr(elf, &ehdr) == NULL) { 1151178479Sjb return (dt_link_error(dtp, elf, fd, bufs, "corrupt file: %s", 1152178479Sjb obj)); 1153178479Sjb } 1154178479Sjb 1155178479Sjb if (dtp->dt_oflags & DTRACE_O_LP64) { 1156178479Sjb eclass = ELFCLASS64; 1157178573Sjb#if defined(__ia64__) 1158178573Sjb emachine1 = emachine2 = EM_IA_64; 1159178573Sjb#elif defined(__mips__) 1160178573Sjb emachine1 = emachine2 = EM_MIPS; 1161178573Sjb#elif defined(__powerpc__) 1162178573Sjb emachine1 = emachine2 = EM_PPC64; 1163178573Sjb#elif defined(__sparc) 1164178479Sjb emachine1 = emachine2 = EM_SPARCV9; 1165178479Sjb#elif defined(__i386) || defined(__amd64) 1166178479Sjb emachine1 = emachine2 = EM_AMD64; 1167178479Sjb#endif 1168178479Sjb symsize = sizeof (Elf64_Sym); 1169178479Sjb } else { 1170178479Sjb eclass = ELFCLASS32; 1171178573Sjb#if defined(__arm__) 1172178573Sjb emachine1 = emachine2 = EM_ARM; 1173178573Sjb#elif defined(__mips__) 1174178573Sjb emachine1 = emachine2 = EM_MIPS; 1175178573Sjb#elif defined(__powerpc__) 1176178573Sjb emachine1 = emachine2 = EM_PPC; 1177178573Sjb#elif defined(__sparc) 1178178479Sjb emachine1 = EM_SPARC; 1179178479Sjb emachine2 = EM_SPARC32PLUS; 1180178573Sjb#elif defined(__i386) || defined(__amd64) || defined(__ia64__) 1181178479Sjb emachine1 = emachine2 = EM_386; 1182178479Sjb#endif 1183178479Sjb symsize = sizeof (Elf32_Sym); 1184178479Sjb } 1185178479Sjb 1186178479Sjb if (ehdr.e_ident[EI_CLASS] != eclass) { 1187178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1188178479Sjb "incorrect ELF class for object file: %s", obj)); 1189178479Sjb } 1190178479Sjb 1191178479Sjb if (ehdr.e_machine != emachine1 && ehdr.e_machine != emachine2) { 1192178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1193178479Sjb "incorrect ELF machine type for object file: %s", obj)); 1194178479Sjb } 1195178479Sjb 1196178479Sjb /* 1197178479Sjb * We use this token as a relatively unique handle for this file on the 1198178479Sjb * system in order to disambiguate potential conflicts between files of 1199178479Sjb * the same name which contain identially named local symbols. 1200178479Sjb */ 1201178479Sjb if ((objkey = ftok(obj, 0)) == (key_t)-1) { 1202178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1203178479Sjb "failed to generate unique key for object file: %s", obj)); 1204178479Sjb } 1205178479Sjb 1206178479Sjb scn_rel = NULL; 1207178479Sjb while ((scn_rel = elf_nextscn(elf, scn_rel)) != NULL) { 1208178479Sjb if (gelf_getshdr(scn_rel, &shdr_rel) == NULL) 1209178479Sjb goto err; 1210178479Sjb 1211178479Sjb /* 1212178479Sjb * Skip any non-relocation sections. 1213178479Sjb */ 1214178479Sjb if (shdr_rel.sh_type != SHT_RELA && shdr_rel.sh_type != SHT_REL) 1215178479Sjb continue; 1216178479Sjb 1217178479Sjb if ((data_rel = elf_getdata(scn_rel, NULL)) == NULL) 1218178479Sjb goto err; 1219178479Sjb 1220178479Sjb /* 1221178479Sjb * Grab the section, section header and section data for the 1222178479Sjb * symbol table that this relocation section references. 1223178479Sjb */ 1224178479Sjb if ((scn_sym = elf_getscn(elf, shdr_rel.sh_link)) == NULL || 1225178479Sjb gelf_getshdr(scn_sym, &shdr_sym) == NULL || 1226178479Sjb (data_sym = elf_getdata(scn_sym, NULL)) == NULL) 1227178479Sjb goto err; 1228178479Sjb 1229178479Sjb /* 1230178479Sjb * Ditto for that symbol table's string table. 1231178479Sjb */ 1232178479Sjb if ((scn_str = elf_getscn(elf, shdr_sym.sh_link)) == NULL || 1233178479Sjb gelf_getshdr(scn_str, &shdr_str) == NULL || 1234178479Sjb (data_str = elf_getdata(scn_str, NULL)) == NULL) 1235178479Sjb goto err; 1236178479Sjb 1237178479Sjb /* 1238178479Sjb * Grab the section, section header and section data for the 1239178479Sjb * target section for the relocations. For the relocations 1240178479Sjb * we're looking for -- this will typically be the text of the 1241178479Sjb * object file. 1242178479Sjb */ 1243178479Sjb if ((scn_tgt = elf_getscn(elf, shdr_rel.sh_info)) == NULL || 1244178479Sjb gelf_getshdr(scn_tgt, &shdr_tgt) == NULL || 1245178479Sjb (data_tgt = elf_getdata(scn_tgt, NULL)) == NULL) 1246178479Sjb goto err; 1247178479Sjb 1248178479Sjb /* 1249178479Sjb * We're looking for relocations to symbols matching this form: 1250178479Sjb * 1251178479Sjb * __dtrace[enabled]_<prov>___<probe> 1252178479Sjb * 1253178479Sjb * For the generated object, we need to record the location 1254178479Sjb * identified by the relocation, and create a new relocation 1255178479Sjb * in the generated object that will be resolved at link time 1256178479Sjb * to the location of the function in which the probe is 1257178479Sjb * embedded. In the target object, we change the matched symbol 1258178479Sjb * so that it will be ignored at link time, and we modify the 1259178479Sjb * target (text) section to replace the call instruction with 1260178479Sjb * one or more nops. 1261178479Sjb * 1262178479Sjb * If the function containing the probe is locally scoped 1263178479Sjb * (static), we create an alias used by the relocation in the 1264178479Sjb * generated object. The alias, a new symbol, will be global 1265178479Sjb * (so that the relocation from the generated object can be 1266178479Sjb * resolved), and hidden (so that it is converted to a local 1267178479Sjb * symbol at link time). Such aliases have this form: 1268178479Sjb * 1269178479Sjb * $dtrace<key>.<function> 1270178479Sjb * 1271178479Sjb * We take a first pass through all the relocations to 1272178479Sjb * populate our string table and count the number of extra 1273178479Sjb * symbols we'll require. 1274178479Sjb */ 1275178479Sjb strtab = dt_strtab_create(1); 1276178479Sjb nsym = 0; 1277178479Sjb isym = data_sym->d_size / symsize; 1278178479Sjb istr = data_str->d_size; 1279178479Sjb 1280178479Sjb for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { 1281178479Sjb 1282178479Sjb if (shdr_rel.sh_type == SHT_RELA) { 1283178479Sjb if (gelf_getrela(data_rel, i, &rela) == NULL) 1284178479Sjb continue; 1285178479Sjb } else { 1286178479Sjb GElf_Rel rel; 1287178479Sjb if (gelf_getrel(data_rel, i, &rel) == NULL) 1288178479Sjb continue; 1289178479Sjb rela.r_offset = rel.r_offset; 1290178479Sjb rela.r_info = rel.r_info; 1291178479Sjb rela.r_addend = 0; 1292178479Sjb } 1293178479Sjb 1294178479Sjb if (gelf_getsym(data_sym, GELF_R_SYM(rela.r_info), 1295178479Sjb &rsym) == NULL) { 1296178479Sjb dt_strtab_destroy(strtab); 1297178479Sjb goto err; 1298178479Sjb } 1299178479Sjb 1300178479Sjb s = (char *)data_str->d_buf + rsym.st_name; 1301178479Sjb 1302178479Sjb if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0) 1303178479Sjb continue; 1304178479Sjb 1305178479Sjb if (dt_symtab_lookup(data_sym, isym, rela.r_offset, 1306178479Sjb shdr_rel.sh_info, &fsym) != 0) { 1307178479Sjb dt_strtab_destroy(strtab); 1308178479Sjb goto err; 1309178479Sjb } 1310178479Sjb 1311178479Sjb if (GELF_ST_BIND(fsym.st_info) != STB_LOCAL) 1312178479Sjb continue; 1313178479Sjb 1314178479Sjb if (fsym.st_name > data_str->d_size) { 1315178479Sjb dt_strtab_destroy(strtab); 1316178479Sjb goto err; 1317178479Sjb } 1318178479Sjb 1319178479Sjb s = (char *)data_str->d_buf + fsym.st_name; 1320178479Sjb 1321178479Sjb /* 1322178479Sjb * If this symbol isn't of type function, we've really 1323178479Sjb * driven off the rails or the object file is corrupt. 1324178479Sjb */ 1325178479Sjb if (GELF_ST_TYPE(fsym.st_info) != STT_FUNC) { 1326178479Sjb dt_strtab_destroy(strtab); 1327178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1328178479Sjb "expected %s to be of type function", s)); 1329178479Sjb } 1330178479Sjb 1331178479Sjb len = snprintf(NULL, 0, dt_symfmt, dt_symprefix, 1332178479Sjb objkey, s) + 1; 1333178479Sjb if ((p = dt_alloc(dtp, len)) == NULL) { 1334178479Sjb dt_strtab_destroy(strtab); 1335178479Sjb goto err; 1336178479Sjb } 1337178479Sjb (void) snprintf(p, len, dt_symfmt, dt_symprefix, 1338178479Sjb objkey, s); 1339178479Sjb 1340178479Sjb if (dt_strtab_index(strtab, p) == -1) { 1341178479Sjb nsym++; 1342178479Sjb (void) dt_strtab_insert(strtab, p); 1343178479Sjb } 1344178479Sjb 1345178479Sjb dt_free(dtp, p); 1346178479Sjb } 1347178479Sjb 1348178479Sjb /* 1349178479Sjb * If needed, allocate the additional space for the symbol 1350178479Sjb * table and string table copying the old data into the new 1351178479Sjb * buffers, and marking the buffers as dirty. We inject those 1352178479Sjb * newly allocated buffers into the libelf data structures, but 1353178479Sjb * are still responsible for freeing them once we're done with 1354178479Sjb * the elf handle. 1355178479Sjb */ 1356178479Sjb if (nsym > 0) { 1357178479Sjb /* 1358178479Sjb * The first byte of the string table is reserved for 1359178479Sjb * the \0 entry. 1360178479Sjb */ 1361178479Sjb len = dt_strtab_size(strtab) - 1; 1362178479Sjb 1363178479Sjb assert(len > 0); 1364178479Sjb assert(dt_strtab_index(strtab, "") == 0); 1365178479Sjb 1366178479Sjb dt_strtab_destroy(strtab); 1367178479Sjb 1368178479Sjb if ((pair = dt_alloc(dtp, sizeof (*pair))) == NULL) 1369178479Sjb goto err; 1370178479Sjb 1371178479Sjb if ((pair->dlp_str = dt_alloc(dtp, data_str->d_size + 1372178479Sjb len)) == NULL) { 1373178479Sjb dt_free(dtp, pair); 1374178479Sjb goto err; 1375178479Sjb } 1376178479Sjb 1377178479Sjb if ((pair->dlp_sym = dt_alloc(dtp, data_sym->d_size + 1378178479Sjb nsym * symsize)) == NULL) { 1379178479Sjb dt_free(dtp, pair->dlp_str); 1380178479Sjb dt_free(dtp, pair); 1381178479Sjb goto err; 1382178479Sjb } 1383178479Sjb 1384178479Sjb pair->dlp_next = bufs; 1385178479Sjb bufs = pair; 1386178479Sjb 1387178479Sjb bcopy(data_str->d_buf, pair->dlp_str, data_str->d_size); 1388178479Sjb data_str->d_buf = pair->dlp_str; 1389178479Sjb data_str->d_size += len; 1390178479Sjb (void) elf_flagdata(data_str, ELF_C_SET, ELF_F_DIRTY); 1391178479Sjb 1392178479Sjb shdr_str.sh_size += len; 1393178479Sjb (void) gelf_update_shdr(scn_str, &shdr_str); 1394178479Sjb 1395178479Sjb bcopy(data_sym->d_buf, pair->dlp_sym, data_sym->d_size); 1396178479Sjb data_sym->d_buf = pair->dlp_sym; 1397178479Sjb data_sym->d_size += nsym * symsize; 1398178479Sjb (void) elf_flagdata(data_sym, ELF_C_SET, ELF_F_DIRTY); 1399178479Sjb 1400178479Sjb shdr_sym.sh_size += nsym * symsize; 1401178479Sjb (void) gelf_update_shdr(scn_sym, &shdr_sym); 1402178479Sjb 1403178479Sjb nsym += isym; 1404178479Sjb } else { 1405178479Sjb dt_strtab_destroy(strtab); 1406178479Sjb } 1407178479Sjb 1408178479Sjb /* 1409178479Sjb * Now that the tables have been allocated, perform the 1410178479Sjb * modifications described above. 1411178479Sjb */ 1412178479Sjb for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { 1413178479Sjb 1414178479Sjb if (shdr_rel.sh_type == SHT_RELA) { 1415178479Sjb if (gelf_getrela(data_rel, i, &rela) == NULL) 1416178479Sjb continue; 1417178479Sjb } else { 1418178479Sjb GElf_Rel rel; 1419178479Sjb if (gelf_getrel(data_rel, i, &rel) == NULL) 1420178479Sjb continue; 1421178479Sjb rela.r_offset = rel.r_offset; 1422178479Sjb rela.r_info = rel.r_info; 1423178479Sjb rela.r_addend = 0; 1424178479Sjb } 1425178479Sjb 1426178479Sjb ndx = GELF_R_SYM(rela.r_info); 1427178479Sjb 1428178479Sjb if (gelf_getsym(data_sym, ndx, &rsym) == NULL || 1429178479Sjb rsym.st_name > data_str->d_size) 1430178479Sjb goto err; 1431178479Sjb 1432178479Sjb s = (char *)data_str->d_buf + rsym.st_name; 1433178479Sjb 1434178479Sjb if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0) 1435178479Sjb continue; 1436178479Sjb 1437178479Sjb s += sizeof (dt_prefix) - 1; 1438178479Sjb 1439178479Sjb /* 1440178479Sjb * Check to see if this is an 'is-enabled' check as 1441178479Sjb * opposed to a normal probe. 1442178479Sjb */ 1443178479Sjb if (strncmp(s, dt_enabled, 1444178479Sjb sizeof (dt_enabled) - 1) == 0) { 1445178479Sjb s += sizeof (dt_enabled) - 1; 1446178479Sjb eprobe = 1; 1447178479Sjb *eprobesp = 1; 1448178479Sjb dt_dprintf("is-enabled probe\n"); 1449178479Sjb } else { 1450178479Sjb eprobe = 0; 1451178479Sjb dt_dprintf("normal probe\n"); 1452178479Sjb } 1453178479Sjb 1454178479Sjb if (*s++ != '_') 1455178479Sjb goto err; 1456178479Sjb 1457178479Sjb if ((p = strstr(s, "___")) == NULL || 1458178479Sjb p - s >= sizeof (pname)) 1459178479Sjb goto err; 1460178479Sjb 1461178479Sjb bcopy(s, pname, p - s); 1462178479Sjb pname[p - s] = '\0'; 1463178479Sjb 1464178479Sjb p = strhyphenate(p + 3); /* strlen("___") */ 1465178479Sjb 1466178479Sjb if (dt_symtab_lookup(data_sym, isym, rela.r_offset, 1467178479Sjb shdr_rel.sh_info, &fsym) != 0) 1468178479Sjb goto err; 1469178479Sjb 1470178479Sjb if (fsym.st_name > data_str->d_size) 1471178479Sjb goto err; 1472178479Sjb 1473178479Sjb assert(GELF_ST_TYPE(fsym.st_info) == STT_FUNC); 1474178479Sjb 1475178479Sjb /* 1476178479Sjb * If a NULL relocation name is passed to 1477178479Sjb * dt_probe_define(), the function name is used for the 1478178479Sjb * relocation. The relocation needs to use a mangled 1479178479Sjb * name if the symbol is locally scoped; the function 1480178479Sjb * name may need to change if we've found the global 1481178479Sjb * alias for the locally scoped symbol (we prefer 1482178479Sjb * global symbols to locals in dt_symtab_lookup()). 1483178479Sjb */ 1484178479Sjb s = (char *)data_str->d_buf + fsym.st_name; 1485178479Sjb r = NULL; 1486178479Sjb 1487178479Sjb if (GELF_ST_BIND(fsym.st_info) == STB_LOCAL) { 1488178479Sjb dsym = fsym; 1489178479Sjb dsym.st_name = istr; 1490178479Sjb dsym.st_info = GELF_ST_INFO(STB_GLOBAL, 1491178479Sjb STT_FUNC); 1492178479Sjb dsym.st_other = 1493178479Sjb ELF64_ST_VISIBILITY(STV_ELIMINATE); 1494178479Sjb (void) gelf_update_sym(data_sym, isym, &dsym); 1495178479Sjb 1496178479Sjb r = (char *)data_str->d_buf + istr; 1497178479Sjb istr += 1 + sprintf(r, dt_symfmt, 1498178479Sjb dt_symprefix, objkey, s); 1499178479Sjb isym++; 1500178479Sjb assert(isym <= nsym); 1501178479Sjb 1502178479Sjb } else if (strncmp(s, dt_symprefix, 1503178479Sjb strlen(dt_symprefix)) == 0) { 1504178479Sjb r = s; 1505178479Sjb if ((s = strchr(s, '.')) == NULL) 1506178479Sjb goto err; 1507178479Sjb s++; 1508178479Sjb } 1509178479Sjb 1510178479Sjb if ((pvp = dt_provider_lookup(dtp, pname)) == NULL) { 1511178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1512178479Sjb "no such provider %s", pname)); 1513178479Sjb } 1514178479Sjb 1515178479Sjb if ((prp = dt_probe_lookup(pvp, p)) == NULL) { 1516178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1517178479Sjb "no such probe %s", p)); 1518178479Sjb } 1519178479Sjb 1520178479Sjb assert(fsym.st_value <= rela.r_offset); 1521178479Sjb 1522178479Sjb off = rela.r_offset - fsym.st_value; 1523178479Sjb if (dt_modtext(dtp, data_tgt->d_buf, eprobe, 1524211554Srpaulo &rela, &off) != 0) 1525178479Sjb goto err; 1526178479Sjb 1527178479Sjb if (dt_probe_define(pvp, prp, s, r, off, eprobe) != 0) { 1528178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1529178479Sjb "failed to allocate space for probe")); 1530178479Sjb } 1531211554Srpaulo#if !defined(sun) 1532211554Srpaulo /* 1533211554Srpaulo * Our linker doesn't understand the SUNW_IGNORE ndx and 1534211554Srpaulo * will try to use this relocation when we build the 1535211554Srpaulo * final executable. Since we are done processing this 1536211554Srpaulo * relocation, mark it as inexistant and let libelf 1537211554Srpaulo * remove it from the file. 1538211554Srpaulo * If this wasn't done, we would have garbage added to 1539211554Srpaulo * the executable file as the symbol is going to be 1540211554Srpaulo * change from UND to ABS. 1541211554Srpaulo */ 1542262061Smarkj if (shdr_rel.sh_type == SHT_RELA) { 1543262061Smarkj rela.r_offset = 0; 1544262061Smarkj rela.r_info = 0; 1545262061Smarkj rela.r_addend = 0; 1546262061Smarkj (void) gelf_update_rela(data_rel, i, &rela); 1547262061Smarkj } else { 1548262061Smarkj GElf_Rel rel; 1549262061Smarkj rel.r_offset = 0; 1550262061Smarkj rel.r_info = 0; 1551262061Smarkj (void) gelf_update_rel(data_rel, i, &rel); 1552262061Smarkj } 1553211554Srpaulo#endif 1554178479Sjb 1555178479Sjb mod = 1; 1556178479Sjb (void) elf_flagdata(data_tgt, ELF_C_SET, ELF_F_DIRTY); 1557178479Sjb 1558178479Sjb /* 1559178479Sjb * This symbol may already have been marked to 1560178479Sjb * be ignored by another relocation referencing 1561178479Sjb * the same symbol or if this object file has 1562178479Sjb * already been processed by an earlier link 1563178479Sjb * invocation. 1564178479Sjb */ 1565211554Srpaulo#if !defined(sun) 1566211554Srpaulo#define SHN_SUNW_IGNORE SHN_ABS 1567211554Srpaulo#endif 1568178479Sjb if (rsym.st_shndx != SHN_SUNW_IGNORE) { 1569178479Sjb rsym.st_shndx = SHN_SUNW_IGNORE; 1570178479Sjb (void) gelf_update_sym(data_sym, ndx, &rsym); 1571178479Sjb } 1572178479Sjb } 1573178479Sjb } 1574178479Sjb 1575178479Sjb if (mod && elf_update(elf, ELF_C_WRITE) == -1) 1576178479Sjb goto err; 1577178479Sjb 1578178479Sjb (void) elf_end(elf); 1579178479Sjb (void) close(fd); 1580178479Sjb 1581211554Srpaulo#if !defined(sun) 1582211554Srpaulo if (nsym > 0) 1583211554Srpaulo#endif 1584178479Sjb while ((pair = bufs) != NULL) { 1585178479Sjb bufs = pair->dlp_next; 1586178479Sjb dt_free(dtp, pair->dlp_str); 1587178479Sjb dt_free(dtp, pair->dlp_sym); 1588178479Sjb dt_free(dtp, pair); 1589178479Sjb } 1590178479Sjb 1591178479Sjb return (0); 1592178479Sjb 1593178479Sjberr: 1594178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1595178479Sjb "an error was encountered while processing %s", obj)); 1596178479Sjb} 1597178479Sjb 1598178479Sjbint 1599178479Sjbdtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags, 1600178479Sjb const char *file, int objc, char *const objv[]) 1601178479Sjb{ 1602178573Sjb#if !defined(sun) 1603178573Sjb char tfile[PATH_MAX]; 1604211554Srpaulo Elf *e; 1605211554Srpaulo Elf_Scn *scn; 1606211554Srpaulo Elf_Data *data; 1607211554Srpaulo GElf_Shdr shdr; 1608211554Srpaulo int efd; 1609211554Srpaulo size_t stridx; 1610211554Srpaulo unsigned char *buf; 1611211554Srpaulo char *s; 1612211554Srpaulo int loc; 1613211554Srpaulo GElf_Ehdr ehdr; 1614211554Srpaulo Elf_Scn *scn0; 1615211554Srpaulo GElf_Shdr shdr0; 1616211554Srpaulo uint64_t off, rc; 1617178573Sjb#endif 1618178479Sjb char drti[PATH_MAX]; 1619178479Sjb dof_hdr_t *dof; 1620178479Sjb int fd, status, i, cur; 1621178479Sjb char *cmd, tmp; 1622178479Sjb size_t len; 1623178479Sjb int eprobes = 0, ret = 0; 1624178479Sjb 1625178573Sjb#if !defined(sun) 1626212358Srpaulo if (access(file, R_OK) == 0) { 1627212358Srpaulo fprintf(stderr, "dtrace: target object (%s) already exists. " 1628212358Srpaulo "Please remove the target\ndtrace: object and rebuild all " 1629212358Srpaulo "the source objects if you wish to run the DTrace\n" 1630212358Srpaulo "dtrace: linking process again\n", file); 1631212358Srpaulo /* 1632212358Srpaulo * Several build infrastructures run DTrace twice (e.g. 1633212358Srpaulo * postgres) and we don't want the build to fail. Return 1634212358Srpaulo * 0 here since this isn't really a fatal error. 1635212358Srpaulo */ 1636212358Srpaulo return (0); 1637212358Srpaulo } 1638178573Sjb /* XXX Should get a temp file name here. */ 1639178573Sjb snprintf(tfile, sizeof(tfile), "%s.tmp", file); 1640178573Sjb#endif 1641178573Sjb 1642178479Sjb /* 1643178479Sjb * A NULL program indicates a special use in which we just link 1644178479Sjb * together a bunch of object files specified in objv and then 1645178479Sjb * unlink(2) those object files. 1646178479Sjb */ 1647178479Sjb if (pgp == NULL) { 1648178479Sjb const char *fmt = "%s -o %s -r"; 1649178479Sjb 1650178479Sjb len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file) + 1; 1651178479Sjb 1652178479Sjb for (i = 0; i < objc; i++) 1653178479Sjb len += strlen(objv[i]) + 1; 1654178479Sjb 1655178479Sjb cmd = alloca(len); 1656178479Sjb 1657178479Sjb cur = snprintf(cmd, len, fmt, dtp->dt_ld_path, file); 1658178479Sjb 1659178479Sjb for (i = 0; i < objc; i++) 1660178479Sjb cur += snprintf(cmd + cur, len - cur, " %s", objv[i]); 1661178479Sjb 1662178479Sjb if ((status = system(cmd)) == -1) { 1663178479Sjb return (dt_link_error(dtp, NULL, -1, NULL, 1664178479Sjb "failed to run %s: %s", dtp->dt_ld_path, 1665178479Sjb strerror(errno))); 1666178479Sjb } 1667178479Sjb 1668178479Sjb if (WIFSIGNALED(status)) { 1669178479Sjb return (dt_link_error(dtp, NULL, -1, NULL, 1670178479Sjb "failed to link %s: %s failed due to signal %d", 1671178479Sjb file, dtp->dt_ld_path, WTERMSIG(status))); 1672178479Sjb } 1673178479Sjb 1674178479Sjb if (WEXITSTATUS(status) != 0) { 1675178479Sjb return (dt_link_error(dtp, NULL, -1, NULL, 1676178479Sjb "failed to link %s: %s exited with status %d\n", 1677178479Sjb file, dtp->dt_ld_path, WEXITSTATUS(status))); 1678178479Sjb } 1679178479Sjb 1680178479Sjb for (i = 0; i < objc; i++) { 1681178479Sjb if (strcmp(objv[i], file) != 0) 1682178479Sjb (void) unlink(objv[i]); 1683178479Sjb } 1684178479Sjb 1685178479Sjb return (0); 1686178479Sjb } 1687178479Sjb 1688178479Sjb for (i = 0; i < objc; i++) { 1689178479Sjb if (process_obj(dtp, objv[i], &eprobes) != 0) 1690178479Sjb return (-1); /* errno is set for us */ 1691178479Sjb } 1692178479Sjb 1693178479Sjb /* 1694178479Sjb * If there are is-enabled probes then we need to force use of DOF 1695178479Sjb * version 2. 1696178479Sjb */ 1697178479Sjb if (eprobes && pgp->dp_dofversion < DOF_VERSION_2) 1698178479Sjb pgp->dp_dofversion = DOF_VERSION_2; 1699178479Sjb 1700178479Sjb if ((dof = dtrace_dof_create(dtp, pgp, dflags)) == NULL) 1701178479Sjb return (-1); /* errno is set for us */ 1702178479Sjb 1703178573Sjb#if defined(sun) 1704178479Sjb /* 1705178479Sjb * Create a temporary file and then unlink it if we're going to 1706178479Sjb * combine it with drti.o later. We can still refer to it in child 1707178479Sjb * processes as /dev/fd/<fd>. 1708178479Sjb */ 1709178479Sjb if ((fd = open64(file, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) { 1710178479Sjb return (dt_link_error(dtp, NULL, -1, NULL, 1711178479Sjb "failed to open %s: %s", file, strerror(errno))); 1712178479Sjb } 1713178573Sjb#else 1714178573Sjb if ((fd = open(tfile, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) 1715178573Sjb return (dt_link_error(dtp, NULL, -1, NULL, 1716178573Sjb "failed to open %s: %s", tfile, strerror(errno))); 1717178573Sjb#endif 1718178479Sjb 1719178479Sjb /* 1720178479Sjb * If -xlinktype=DOF has been selected, just write out the DOF. 1721178479Sjb * Otherwise proceed to the default of generating and linking ELF. 1722178479Sjb */ 1723178479Sjb switch (dtp->dt_linktype) { 1724178479Sjb case DT_LTYP_DOF: 1725178479Sjb if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz) 1726178479Sjb ret = errno; 1727178479Sjb 1728178479Sjb if (close(fd) != 0 && ret == 0) 1729178479Sjb ret = errno; 1730178479Sjb 1731178479Sjb if (ret != 0) { 1732178479Sjb return (dt_link_error(dtp, NULL, -1, NULL, 1733178479Sjb "failed to write %s: %s", file, strerror(ret))); 1734178479Sjb } 1735178479Sjb 1736178479Sjb return (0); 1737178479Sjb 1738178479Sjb case DT_LTYP_ELF: 1739178479Sjb break; /* fall through to the rest of dtrace_program_link() */ 1740178479Sjb 1741178479Sjb default: 1742178479Sjb return (dt_link_error(dtp, NULL, -1, NULL, 1743178479Sjb "invalid link type %u\n", dtp->dt_linktype)); 1744178479Sjb } 1745178479Sjb 1746178479Sjb 1747178573Sjb#if defined(sun) 1748178479Sjb if (!dtp->dt_lazyload) 1749178479Sjb (void) unlink(file); 1750178573Sjb#endif 1751178479Sjb 1752211554Srpaulo#if defined(sun) 1753178479Sjb if (dtp->dt_oflags & DTRACE_O_LP64) 1754178479Sjb status = dump_elf64(dtp, dof, fd); 1755178479Sjb else 1756178479Sjb status = dump_elf32(dtp, dof, fd); 1757178479Sjb 1758178479Sjb if (status != 0 || lseek(fd, 0, SEEK_SET) != 0) { 1759211554Srpaulo#else 1760211554Srpaulo /* We don't write the ELF header, just the DOF section */ 1761211554Srpaulo if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz) { 1762211554Srpaulo#endif 1763178479Sjb return (dt_link_error(dtp, NULL, -1, NULL, 1764178479Sjb "failed to write %s: %s", file, strerror(errno))); 1765178479Sjb } 1766178479Sjb 1767178479Sjb if (!dtp->dt_lazyload) { 1768178573Sjb#if defined(sun) 1769178479Sjb const char *fmt = "%s -o %s -r -Blocal -Breduce /dev/fd/%d %s"; 1770178479Sjb 1771178479Sjb if (dtp->dt_oflags & DTRACE_O_LP64) { 1772178479Sjb (void) snprintf(drti, sizeof (drti), 1773178479Sjb "%s/64/drti.o", _dtrace_libdir); 1774178479Sjb } else { 1775178479Sjb (void) snprintf(drti, sizeof (drti), 1776178479Sjb "%s/drti.o", _dtrace_libdir); 1777178479Sjb } 1778178479Sjb 1779178479Sjb len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, fd, 1780178479Sjb drti) + 1; 1781178479Sjb 1782178479Sjb cmd = alloca(len); 1783178479Sjb 1784178479Sjb (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, fd, drti); 1785178573Sjb#else 1786211554Srpaulo const char *fmt = "%s -o %s -r %s"; 1787178479Sjb 1788178573Sjb#if defined(__amd64__) 1789178573Sjb /* 1790178573Sjb * Arches which default to 64-bit need to explicitly use 1791178573Sjb * the 32-bit library path. 1792178573Sjb */ 1793178573Sjb int use_32 = !(dtp->dt_oflags & DTRACE_O_LP64); 1794178573Sjb#else 1795178573Sjb /* 1796178573Sjb * Arches which are 32-bit only just use the normal 1797178573Sjb * library path. 1798178573Sjb */ 1799178573Sjb int use_32 = 0; 1800178573Sjb#endif 1801178573Sjb 1802178573Sjb (void) snprintf(drti, sizeof (drti), "/usr/lib%s/dtrace/drti.o", 1803187347Sjhb use_32 ? "32":""); 1804178573Sjb 1805178573Sjb len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, tfile, 1806178573Sjb drti) + 1; 1807178573Sjb 1808211554Srpaulo#if !defined(sun) 1809211554Srpaulo len *= 2; 1810211554Srpaulo#endif 1811178573Sjb cmd = alloca(len); 1812178573Sjb 1813211554Srpaulo (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, 1814211554Srpaulo drti); 1815178573Sjb#endif 1816178479Sjb if ((status = system(cmd)) == -1) { 1817178479Sjb ret = dt_link_error(dtp, NULL, -1, NULL, 1818178479Sjb "failed to run %s: %s", dtp->dt_ld_path, 1819178479Sjb strerror(errno)); 1820178479Sjb goto done; 1821178479Sjb } 1822178479Sjb 1823178479Sjb if (WIFSIGNALED(status)) { 1824178479Sjb ret = dt_link_error(dtp, NULL, -1, NULL, 1825178479Sjb "failed to link %s: %s failed due to signal %d", 1826178479Sjb file, dtp->dt_ld_path, WTERMSIG(status)); 1827178479Sjb goto done; 1828178479Sjb } 1829178479Sjb 1830178479Sjb if (WEXITSTATUS(status) != 0) { 1831178479Sjb ret = dt_link_error(dtp, NULL, -1, NULL, 1832178479Sjb "failed to link %s: %s exited with status %d\n", 1833178479Sjb file, dtp->dt_ld_path, WEXITSTATUS(status)); 1834178479Sjb goto done; 1835178479Sjb } 1836211554Srpaulo#if !defined(sun) 1837211554Srpaulo#define BROKEN_LIBELF 1838211554Srpaulo /* 1839211554Srpaulo * FreeBSD's ld(1) is not instructed to interpret and add 1840211554Srpaulo * correctly the SUNW_dof section present in tfile. 1841211554Srpaulo * We use libelf to add this section manually and hope the next 1842211554Srpaulo * ld invocation won't remove it. 1843211554Srpaulo */ 1844211554Srpaulo elf_version(EV_CURRENT); 1845211554Srpaulo if ((efd = open(file, O_RDWR, 0)) < 0) { 1846211554Srpaulo ret = dt_link_error(dtp, NULL, -1, NULL, 1847211554Srpaulo "failed to open file %s: %s", 1848211554Srpaulo file, strerror(errno)); 1849211554Srpaulo goto done; 1850211554Srpaulo } 1851211554Srpaulo if ((e = elf_begin(efd, ELF_C_RDWR, NULL)) == NULL) { 1852211554Srpaulo close(efd); 1853211554Srpaulo ret = dt_link_error(dtp, NULL, -1, NULL, 1854211554Srpaulo "failed to open elf file: %s", 1855211554Srpaulo elf_errmsg(elf_errno())); 1856211554Srpaulo goto done; 1857211554Srpaulo } 1858211554Srpaulo /* 1859211554Srpaulo * Add the string '.SUWN_dof' to the shstrtab section. 1860211554Srpaulo */ 1861211554Srpaulo#ifdef BROKEN_LIBELF 1862211554Srpaulo elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT); 1863211554Srpaulo#endif 1864211554Srpaulo elf_getshdrstrndx(e, &stridx); 1865211554Srpaulo scn = elf_getscn(e, stridx); 1866211554Srpaulo gelf_getshdr(scn, &shdr); 1867211554Srpaulo data = elf_newdata(scn); 1868211554Srpaulo data->d_off = shdr.sh_size; 1869211554Srpaulo data->d_buf = ".SUNW_dof"; 1870211554Srpaulo data->d_size = 10; 1871211554Srpaulo data->d_type = ELF_T_BYTE; 1872211554Srpaulo loc = shdr.sh_size; 1873211554Srpaulo shdr.sh_size += data->d_size; 1874211554Srpaulo gelf_update_shdr(scn, &shdr); 1875211554Srpaulo#ifdef BROKEN_LIBELF 1876211554Srpaulo off = shdr.sh_offset; 1877211554Srpaulo rc = shdr.sh_offset + shdr.sh_size; 1878211554Srpaulo gelf_getehdr(e, &ehdr); 1879211554Srpaulo if (ehdr.e_shoff > off) { 1880211554Srpaulo off = ehdr.e_shoff + ehdr.e_shnum * ehdr.e_shentsize; 1881211554Srpaulo rc = roundup(rc, 8); 1882211554Srpaulo ehdr.e_shoff = rc; 1883211554Srpaulo gelf_update_ehdr(e, &ehdr); 1884211554Srpaulo rc += ehdr.e_shnum * ehdr.e_shentsize; 1885211554Srpaulo } 1886211554Srpaulo for (;;) { 1887211554Srpaulo scn0 = NULL; 1888211554Srpaulo scn = NULL; 1889211554Srpaulo while ((scn = elf_nextscn(e, scn)) != NULL) { 1890211554Srpaulo gelf_getshdr(scn, &shdr); 1891211554Srpaulo if (shdr.sh_type == SHT_NOBITS || 1892211554Srpaulo shdr.sh_offset < off) 1893211554Srpaulo continue; 1894211554Srpaulo /* Find the immediately adjcent section. */ 1895211554Srpaulo if (scn0 == NULL || 1896211554Srpaulo shdr.sh_offset < shdr0.sh_offset) { 1897211554Srpaulo scn0 = scn; 1898211554Srpaulo gelf_getshdr(scn0, &shdr0); 1899211554Srpaulo } 1900211554Srpaulo } 1901211554Srpaulo if (scn0 == NULL) 1902211554Srpaulo break; 1903211554Srpaulo /* Load section data to work around another bug */ 1904211554Srpaulo elf_getdata(scn0, NULL); 1905211554Srpaulo /* Update section header, assure section alignment */ 1906211554Srpaulo off = shdr0.sh_offset + shdr0.sh_size; 1907211554Srpaulo rc = roundup(rc, shdr0.sh_addralign); 1908211554Srpaulo shdr0.sh_offset = rc; 1909211554Srpaulo gelf_update_shdr(scn0, &shdr0); 1910211554Srpaulo rc += shdr0.sh_size; 1911211554Srpaulo } 1912211554Srpaulo if (elf_update(e, ELF_C_WRITE) < 0) { 1913211554Srpaulo ret = dt_link_error(dtp, NULL, -1, NULL, 1914211554Srpaulo "failed to add append the shstrtab section: %s", 1915211554Srpaulo elf_errmsg(elf_errno())); 1916211554Srpaulo elf_end(e); 1917211554Srpaulo close(efd); 1918211554Srpaulo goto done; 1919211554Srpaulo } 1920211554Srpaulo elf_end(e); 1921211554Srpaulo e = elf_begin(efd, ELF_C_RDWR, NULL); 1922211554Srpaulo#endif 1923211554Srpaulo /* 1924211554Srpaulo * Construct the .SUNW_dof section. 1925211554Srpaulo */ 1926211554Srpaulo scn = elf_newscn(e); 1927211554Srpaulo data = elf_newdata(scn); 1928211554Srpaulo buf = mmap(NULL, dof->dofh_filesz, PROT_READ, MAP_SHARED, 1929211554Srpaulo fd, 0); 1930211554Srpaulo if (buf == MAP_FAILED) { 1931211554Srpaulo ret = dt_link_error(dtp, NULL, -1, NULL, 1932211554Srpaulo "failed to mmap buffer %s", strerror(errno)); 1933211554Srpaulo elf_end(e); 1934211554Srpaulo close(efd); 1935211554Srpaulo goto done; 1936211554Srpaulo } 1937211554Srpaulo data->d_buf = buf; 1938211554Srpaulo data->d_align = 4; 1939211554Srpaulo data->d_size = dof->dofh_filesz; 1940211554Srpaulo data->d_version = EV_CURRENT; 1941211554Srpaulo gelf_getshdr(scn, &shdr); 1942211554Srpaulo shdr.sh_name = loc; 1943211554Srpaulo shdr.sh_flags = SHF_ALLOC; 1944211554Srpaulo /* 1945211554Srpaulo * Actually this should be SHT_SUNW_dof, but FreeBSD's ld(1) 1946211554Srpaulo * will remove this 'unknown' section when we try to create an 1947211554Srpaulo * executable using the object we are modifying, so we stop 1948211554Srpaulo * playing by the rules and use SHT_PROGBITS. 1949211554Srpaulo * Also, note that our drti has modifications to handle this. 1950211554Srpaulo */ 1951211554Srpaulo shdr.sh_type = SHT_PROGBITS; 1952211554Srpaulo shdr.sh_addralign = 4; 1953211554Srpaulo gelf_update_shdr(scn, &shdr); 1954211554Srpaulo if (elf_update(e, ELF_C_WRITE) < 0) { 1955211554Srpaulo ret = dt_link_error(dtp, NULL, -1, NULL, 1956211554Srpaulo "failed to add the SUNW_dof section: %s", 1957211554Srpaulo elf_errmsg(elf_errno())); 1958211554Srpaulo munmap(buf, dof->dofh_filesz); 1959211554Srpaulo elf_end(e); 1960211554Srpaulo close(efd); 1961211554Srpaulo goto done; 1962211554Srpaulo } 1963211554Srpaulo munmap(buf, dof->dofh_filesz); 1964211554Srpaulo elf_end(e); 1965211554Srpaulo close(efd); 1966211554Srpaulo#endif 1967211554Srpaulo (void) close(fd); /* release temporary file */ 1968178479Sjb } else { 1969178479Sjb (void) close(fd); 1970178479Sjb } 1971178479Sjb 1972178479Sjbdone: 1973178479Sjb dtrace_dof_destroy(dtp, dof); 1974178573Sjb 1975178573Sjb#if !defined(sun) 1976178573Sjb unlink(tfile); 1977178573Sjb#endif 1978178479Sjb return (ret); 1979178479Sjb} 1980