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 /*PRINTFLIKE2*/
872 static int
873 dt_link_error(dtrace_hdl_t *dtp, 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 	return (dt_set_errno(dtp, EDT_COMPILER));
882 }
883 
884 static int
885 process_obj(dtrace_hdl_t *dtp, const char *obj)
886 {
887 	static const char dt_prefix[] = "__dtrace_";
888 	int fd, i, ndx, mod = 0;
889 	Elf *elf;
890 	GElf_Ehdr ehdr;
891 	Elf_Scn *scn_rel, *scn_sym, *scn_tgt;
892 	Elf_Data *data_rel, *data_sym, *data_tgt;
893 	GElf_Shdr shdr_rel, shdr_sym, shdr_tgt;
894 	GElf_Sym rsym, fsym;
895 	GElf_Rela rela;
896 	GElf_Rel rel;
897 	char *s, *p;
898 	char pname[DTRACE_PROVNAMELEN];
899 	dt_provider_t *pvp;
900 	dt_probe_t *prp;
901 	uint32_t off, eclass, emachine1, emachine2;
902 
903 	if ((fd = open64(obj, O_RDWR)) == -1) {
904 		return (dt_link_error(dtp, "failed to open %s: %s", obj,
905 		    strerror(errno)));
906 	}
907 
908 	if (elf_version(EV_CURRENT) == EV_NONE ||
909 	    (elf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL) {
910 		return (dt_link_error(dtp, "failed to process %s: %s", obj,
911 		    elf_errmsg(elf_errno())));
912 	}
913 
914 	switch (elf_kind(elf)) {
915 	case ELF_K_ELF:
916 		break;
917 	case ELF_K_AR:
918 		return (dt_link_error(dtp, "archive files are not permitted %s;"
919 		    " use the contents of the archive instead", obj));
920 	default:
921 		return (dt_link_error(dtp, "invalid file type for %s", obj));
922 	}
923 
924 	if (gelf_getehdr(elf, &ehdr) == NULL)
925 		return (dt_link_error(dtp, "corrupt object file %s", obj));
926 
927 	if (dtp->dt_oflags & DTRACE_O_LP64) {
928 		eclass = ELFCLASS64;
929 #if defined(__sparc)
930 		emachine1 = emachine2 = EM_SPARCV9;
931 #elif defined(__i386) || defined(__amd64)
932 		emachine1 = emachine2 = EM_AMD64;
933 #endif
934 	} else {
935 		eclass = ELFCLASS32;
936 #if defined(__sparc)
937 		emachine1 = EM_SPARC;
938 		emachine2 = EM_SPARC32PLUS;
939 #elif defined(__i386) || defined(__amd64)
940 		emachine1 = emachine2 = EM_386;
941 #endif
942 	}
943 
944 	if (ehdr.e_ident[EI_CLASS] != eclass)
945 		return (dt_link_error(dtp, "incorrect ELF class for object "
946 		    "file %s", obj));
947 
948 	if (ehdr.e_machine != emachine1 && ehdr.e_machine != emachine2)
949 		return (dt_link_error(dtp, "incorrect ELF machine type for "
950 		    "object file %s", obj));
951 
952 	scn_rel = NULL;
953 	while ((scn_rel = elf_nextscn(elf, scn_rel)) != NULL) {
954 		if (gelf_getshdr(scn_rel, &shdr_rel) == NULL)
955 			goto err;
956 
957 		if (shdr_rel.sh_type != SHT_RELA && shdr_rel.sh_type != SHT_REL)
958 			continue;
959 
960 		if ((data_rel = elf_getdata(scn_rel, NULL)) == NULL)
961 			goto err;
962 
963 		if ((scn_sym = elf_getscn(elf, shdr_rel.sh_link)) == NULL ||
964 		    gelf_getshdr(scn_sym, &shdr_sym) == NULL ||
965 		    (data_sym = elf_getdata(scn_sym, NULL)) == NULL)
966 			goto err;
967 
968 		if ((scn_tgt = elf_getscn(elf, shdr_rel.sh_info)) == NULL ||
969 		    gelf_getshdr(scn_tgt, &shdr_tgt) == NULL ||
970 		    (data_tgt = elf_getdata(scn_tgt, NULL)) == NULL)
971 			goto err;
972 
973 		for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) {
974 
975 			if (shdr_rel.sh_type == SHT_RELA) {
976 				if (gelf_getrela(data_rel, i, &rela) == NULL)
977 					continue;
978 			} else {
979 				if (gelf_getrel(data_rel, i, &rel) == NULL)
980 					continue;
981 				rela.r_offset = rel.r_offset;
982 				rela.r_info = rel.r_info;
983 				rela.r_addend = 0;
984 			}
985 
986 			ndx = GELF_R_SYM(rela.r_info);
987 
988 			if (gelf_getsym(data_sym, ndx, &rsym) == NULL ||
989 			    (s = elf_strptr(elf, shdr_sym.sh_link,
990 			    rsym.st_name)) == NULL)
991 				goto err;
992 
993 			if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0)
994 				continue;
995 
996 			if (dt_symtab_lookup(data_sym, rela.r_offset,
997 			    shdr_rel.sh_info, &fsym) != 0)
998 				goto err;
999 
1000 			s += sizeof (dt_prefix) - 1;
1001 			if ((p = strstr(s, "___")) == NULL ||
1002 			    p - s >= sizeof (pname))
1003 				goto err;
1004 
1005 			(void) memcpy(pname, s, p - s);
1006 			pname[p - s] = '\0';
1007 
1008 			p = strhyphenate(p + 3); /* strlen("___") */
1009 
1010 			if ((s = elf_strptr(elf, shdr_sym.sh_link,
1011 			    fsym.st_name)) == NULL)
1012 				goto err;
1013 
1014 			if ((pvp = dt_provider_lookup(dtp, pname)) == NULL) {
1015 				return (dt_link_error(dtp,
1016 				    "no such provider %s", pname));
1017 			}
1018 
1019 			if ((prp = dt_probe_lookup(pvp, p)) == NULL) {
1020 				return (dt_link_error(dtp,
1021 				    "no such probe %s", p));
1022 			}
1023 
1024 			assert(fsym.st_value <= rela.r_offset);
1025 
1026 			off = rela.r_offset - fsym.st_value;
1027 			if (dt_modtext(data_tgt->d_buf, &rela, &off) != 0)
1028 				goto err;
1029 
1030 			if (dt_probe_define(pvp, prp, s, off) != 0)
1031 				return (dt_set_errno(dtp, EDT_NOMEM));
1032 
1033 			mod = 1;
1034 
1035 			/*
1036 			 * This symbol may already have been marked to
1037 			 * be ignored by another relocation referencing
1038 			 * the same symbol or if this object file has
1039 			 * already been processed by an earlier link
1040 			 * invocation.
1041 			 */
1042 			if (rsym.st_shndx != SHN_SUNW_IGNORE) {
1043 				rsym.st_shndx = SHN_SUNW_IGNORE;
1044 				(void) gelf_update_sym(data_sym, ndx, &rsym);
1045 			}
1046 		}
1047 	}
1048 
1049 	if (mod && elf_update(elf, ELF_C_WRITE) == -1)
1050 		goto err;
1051 
1052 	return (0);
1053 
1054 err:
1055 	return (dt_link_error(dtp,
1056 	    "an error was encountered while processing %s", obj));
1057 }
1058 
1059 int
1060 dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
1061     const char *file, int objc, char *const objv[])
1062 {
1063 	char drti[PATH_MAX];
1064 	dof_hdr_t *dof;
1065 	int fd, status, i, cur;
1066 	char *cmd, tmp;
1067 	size_t len;
1068 	int ret = 0;
1069 
1070 	/*
1071 	 * A NULL program indicates a special use in which we just link
1072 	 * together a bunch of object files specified in objv and then
1073 	 * unlink(2) those object files.
1074 	 */
1075 	if (pgp == NULL) {
1076 		const char *fmt = "%s -o %s -r";
1077 
1078 		len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file) + 1;
1079 
1080 		for (i = 0; i < objc; i++)
1081 			len += strlen(objv[i]) + 1;
1082 
1083 		cmd = alloca(len);
1084 
1085 		cur = snprintf(cmd, len, fmt, dtp->dt_ld_path, file);
1086 
1087 		for (i = 0; i < objc; i++)
1088 			cur += snprintf(cmd + cur, len - cur, " %s", objv[i]);
1089 
1090 		if ((status = system(cmd)) == -1) {
1091 			return (dt_link_error(dtp, "failed to run %s: %s",
1092 			    dtp->dt_ld_path, strerror(errno)));
1093 		}
1094 
1095 		if (WIFSIGNALED(status)) {
1096 			return (dt_link_error(dtp,
1097 			    "failed to link %s: %s failed due to signal %d",
1098 			    file, dtp->dt_ld_path, WTERMSIG(status)));
1099 		}
1100 
1101 		if (WEXITSTATUS(status) != 0) {
1102 			return (dt_link_error(dtp,
1103 			    "failed to link %s: %s exited with status %d\n",
1104 			    file, dtp->dt_ld_path, WEXITSTATUS(status)));
1105 		}
1106 
1107 		for (i = 0; i < objc; i++) {
1108 			if (strcmp(objv[i], file) != 0)
1109 				(void) unlink(objv[i]);
1110 		}
1111 
1112 		return (0);
1113 	}
1114 
1115 	for (i = 0; i < objc; i++) {
1116 		if (process_obj(dtp, objv[i]) != 0)
1117 			return (-1); /* errno is set for us */
1118 	}
1119 
1120 	if ((dof = dtrace_dof_create(dtp, pgp, dflags)) == NULL)
1121 		return (-1); /* errno is set for us */
1122 
1123 	/*
1124 	 * Create a temporary file and then unlink it if we're going to
1125 	 * combine it with drti.o later.  We can still refer to it in child
1126 	 * processes as /dev/fd/<fd>.
1127 	 */
1128 	if ((fd = open64(file, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) {
1129 		return (dt_link_error(dtp,
1130 		    "failed to open %s: %s", file, strerror(errno)));
1131 	}
1132 
1133 	/*
1134 	 * If -xlinktype=DOF has been selected, just write out the DOF.
1135 	 * Otherwise proceed to the default of generating and linking ELF.
1136 	 */
1137 	switch (dtp->dt_linktype) {
1138 	case DT_LTYP_DOF:
1139 		if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz)
1140 			ret = errno;
1141 
1142 		if (close(fd) != 0 && ret == 0)
1143 			ret = errno;
1144 
1145 		if (ret != 0) {
1146 			return (dt_link_error(dtp,
1147 			    "failed to write %s: %s", file, strerror(ret)));
1148 		}
1149 
1150 		return (0);
1151 
1152 	case DT_LTYP_ELF:
1153 		break; /* fall through to the rest of dtrace_program_link() */
1154 
1155 	default:
1156 		return (dt_link_error(dtp,
1157 		    "invalid link type %u\n", dtp->dt_linktype));
1158 	}
1159 
1160 
1161 	if (!dtp->dt_lazyload)
1162 		(void) unlink(file);
1163 
1164 	if (dtp->dt_oflags & DTRACE_O_LP64)
1165 		status = dump_elf64(dtp, dof, fd);
1166 	else
1167 		status = dump_elf32(dtp, dof, fd);
1168 
1169 	if (status != 0 || lseek(fd, 0, SEEK_SET) != 0) {
1170 		return (dt_link_error(dtp,
1171 		    "failed to write %s: %s", file, strerror(errno)));
1172 	}
1173 
1174 	if (!dtp->dt_lazyload) {
1175 		const char *fmt = "%s -o %s -r -Blocal -Breduce /dev/fd/%d %s";
1176 
1177 		if (dtp->dt_oflags & DTRACE_O_LP64) {
1178 			(void) snprintf(drti, sizeof (drti),
1179 			    "%s/64/drti.o", _dtrace_libdir);
1180 		} else {
1181 			(void) snprintf(drti, sizeof (drti),
1182 			    "%s/drti.o", _dtrace_libdir);
1183 		}
1184 
1185 		len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, fd,
1186 		    drti) + 1;
1187 
1188 		cmd = alloca(len);
1189 
1190 		(void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, fd, drti);
1191 
1192 		if ((status = system(cmd)) == -1) {
1193 			ret = dt_link_error(dtp, "failed to run %s: %s",
1194 			    dtp->dt_ld_path, strerror(errno));
1195 			goto done;
1196 		}
1197 
1198 		(void) close(fd); /* release temporary file */
1199 
1200 		if (WIFSIGNALED(status)) {
1201 			ret = dt_link_error(dtp,
1202 			    "failed to link %s: %s failed due to signal %d",
1203 			    file, dtp->dt_ld_path, WTERMSIG(status));
1204 			goto done;
1205 		}
1206 
1207 		if (WEXITSTATUS(status) != 0) {
1208 			ret = dt_link_error(dtp,
1209 			    "failed to link %s: %s exited with status %d\n",
1210 			    file, dtp->dt_ld_path, WEXITSTATUS(status));
1211 			goto done;
1212 		}
1213 	} else {
1214 		(void) close(fd);
1215 	}
1216 
1217 done:
1218 	dtrace_dof_destroy(dtp, dof);
1219 	return (ret);
1220 }
1221