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