xref: /freebsd/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c (revision 02e9120893770924227138ba49df1edb3896112a)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  * Copyright 2017-2018 Mark Johnston <markj@FreeBSD.org>
26  */
27 
28 #include <sys/param.h>
29 #include <sys/mman.h>
30 #include <sys/wait.h>
31 
32 #include <assert.h>
33 #include <elf.h>
34 #include <sys/types.h>
35 #include <fcntl.h>
36 #include <gelf.h>
37 #include <limits.h>
38 #include <stddef.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <strings.h>
42 #include <errno.h>
43 #include <unistd.h>
44 
45 #include <libelf.h>
46 
47 #include <dt_impl.h>
48 #include <dt_provider.h>
49 #include <dt_program.h>
50 #include <dt_string.h>
51 
52 #define	ESHDR_NULL	0
53 #define	ESHDR_SHSTRTAB	1
54 #define	ESHDR_DOF	2
55 #define	ESHDR_STRTAB	3
56 #define	ESHDR_SYMTAB	4
57 #define	ESHDR_REL	5
58 #define	ESHDR_NUM	6
59 
60 #define	PWRITE_SCN(index, data) \
61 	(lseek64(fd, (off64_t)elf_file.shdr[(index)].sh_offset, SEEK_SET) != \
62 	(off64_t)elf_file.shdr[(index)].sh_offset || \
63 	dt_write(dtp, fd, (data), elf_file.shdr[(index)].sh_size) != \
64 	elf_file.shdr[(index)].sh_size)
65 
66 static const char DTRACE_SHSTRTAB32[] = "\0"
67 ".shstrtab\0"		/* 1 */
68 ".SUNW_dof\0"		/* 11 */
69 ".strtab\0"		/* 21 */
70 ".symtab\0"		/* 29 */
71 ".rel.SUNW_dof";	/* 37 */
72 
73 static const char DTRACE_SHSTRTAB64[] = "\0"
74 ".shstrtab\0"		/* 1 */
75 ".SUNW_dof\0"		/* 11 */
76 ".strtab\0"		/* 21 */
77 ".symtab\0"		/* 29 */
78 ".rela.SUNW_dof";	/* 37 */
79 
80 static const char DOFSTR[] = "__SUNW_dof";
81 static const char DOFLAZYSTR[] = "___SUNW_dof";
82 
83 typedef struct dt_link_pair {
84 	struct dt_link_pair *dlp_next;	/* next pair in linked list */
85 	void *dlp_str;			/* buffer for string table */
86 	void *dlp_sym;			/* buffer for symbol table */
87 } dt_link_pair_t;
88 
89 typedef struct dof_elf32 {
90 	uint32_t de_nrel;		/* relocation count */
91 	Elf32_Rel *de_rel;		/* array of relocations for x86 */
92 	uint32_t de_nsym;		/* symbol count */
93 	Elf32_Sym *de_sym;		/* array of symbols */
94 	uint32_t de_strlen;		/* size of of string table */
95 	char *de_strtab;		/* string table */
96 	uint32_t de_global;		/* index of the first global symbol */
97 } dof_elf32_t;
98 
99 static int
100 prepare_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf32_t *dep)
101 {
102 	dof_sec_t *dofs, *s;
103 	dof_relohdr_t *dofrh;
104 	dof_relodesc_t *dofr;
105 	char *strtab;
106 	int i, j, nrel;
107 	size_t strtabsz = 1;
108 	uint32_t count = 0;
109 	size_t base;
110 	Elf32_Sym *sym;
111 	Elf32_Rel *rel;
112 
113 	/*LINTED*/
114 	dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff);
115 
116 	/*
117 	 * First compute the size of the string table and the number of
118 	 * relocations present in the DOF.
119 	 */
120 	for (i = 0; i < dof->dofh_secnum; i++) {
121 		if (dofs[i].dofs_type != DOF_SECT_URELHDR)
122 			continue;
123 
124 		/*LINTED*/
125 		dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset);
126 
127 		s = &dofs[dofrh->dofr_strtab];
128 		strtab = (char *)dof + s->dofs_offset;
129 		assert(strtab[0] == '\0');
130 		strtabsz += s->dofs_size - 1;
131 
132 		s = &dofs[dofrh->dofr_relsec];
133 		/*LINTED*/
134 		dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset);
135 		count += s->dofs_size / s->dofs_entsize;
136 	}
137 
138 	dep->de_strlen = strtabsz;
139 	dep->de_nrel = count;
140 	dep->de_nsym = count + 1; /* the first symbol is always null */
141 
142 	if (dtp->dt_lazyload) {
143 		dep->de_strlen += sizeof (DOFLAZYSTR);
144 		dep->de_nsym++;
145 	} else {
146 		dep->de_strlen += sizeof (DOFSTR);
147 		dep->de_nsym++;
148 	}
149 
150 	if ((dep->de_rel = calloc(dep->de_nrel,
151 	    sizeof (dep->de_rel[0]))) == NULL) {
152 		return (dt_set_errno(dtp, EDT_NOMEM));
153 	}
154 
155 	if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf32_Sym))) == NULL) {
156 		free(dep->de_rel);
157 		return (dt_set_errno(dtp, EDT_NOMEM));
158 	}
159 
160 	if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) {
161 		free(dep->de_rel);
162 		free(dep->de_sym);
163 		return (dt_set_errno(dtp, EDT_NOMEM));
164 	}
165 
166 	count = 0;
167 	strtabsz = 1;
168 	dep->de_strtab[0] = '\0';
169 	rel = dep->de_rel;
170 	sym = dep->de_sym;
171 	dep->de_global = 1;
172 
173 	/*
174 	 * The first symbol table entry must be zeroed and is always ignored.
175 	 */
176 	bzero(sym, sizeof (Elf32_Sym));
177 	sym++;
178 
179 	/*
180 	 * Take a second pass through the DOF sections filling in the
181 	 * memory we allocated.
182 	 */
183 	for (i = 0; i < dof->dofh_secnum; i++) {
184 		if (dofs[i].dofs_type != DOF_SECT_URELHDR)
185 			continue;
186 
187 		/*LINTED*/
188 		dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset);
189 
190 		s = &dofs[dofrh->dofr_strtab];
191 		strtab = (char *)dof + s->dofs_offset;
192 		bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size);
193 		base = strtabsz;
194 		strtabsz += s->dofs_size - 1;
195 
196 		s = &dofs[dofrh->dofr_relsec];
197 		/*LINTED*/
198 		dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset);
199 		nrel = s->dofs_size / s->dofs_entsize;
200 
201 		s = &dofs[dofrh->dofr_tgtsec];
202 
203 		for (j = 0; j < nrel; j++) {
204 #if defined(__aarch64__)
205 			rel->r_offset = s->dofs_offset +
206 			    dofr[j].dofr_offset;
207 			rel->r_info = ELF32_R_INFO(count + dep->de_global,
208 			    R_ARM_REL32);
209 #elif defined(__arm__)
210 /* XXX */
211 			printf("%s:%s(%d): arm not implemented\n",
212 			    __FUNCTION__, __FILE__, __LINE__);
213 #elif defined(__i386) || defined(__amd64)
214 			rel->r_offset = s->dofs_offset +
215 			    dofr[j].dofr_offset;
216 			rel->r_info = ELF32_R_INFO(count + dep->de_global,
217 			    R_386_PC32);
218 #elif defined(__powerpc__)
219 			/*
220 			 * Add 4 bytes to hit the low half of this 64-bit
221 			 * big-endian address.
222 			 */
223 			rel->r_offset = s->dofs_offset +
224 			    dofr[j].dofr_offset + 4;
225 			rel->r_info = ELF32_R_INFO(count + dep->de_global,
226 			    R_PPC_REL32);
227 #elif defined(__riscv)
228 			rel->r_offset = s->dofs_offset + dofr[j].dofr_offset;
229 			rel->r_info = ELF32_R_INFO(count + dep->de_global,
230 			    R_RISCV_32_PCREL);
231 #else
232 #error unknown ISA
233 #endif
234 
235 			sym->st_name = base + dofr[j].dofr_name - 1;
236 			sym->st_value = 0;
237 			sym->st_size = 0;
238 			sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_FUNC);
239 			sym->st_other = ELF32_ST_VISIBILITY(STV_HIDDEN);
240 			sym->st_shndx = SHN_UNDEF;
241 
242 			rel++;
243 			sym++;
244 			count++;
245 		}
246 	}
247 
248 	/*
249 	 * Add a symbol for the DOF itself. We use a different symbol for
250 	 * lazily and actively loaded DOF to make them easy to distinguish.
251 	 */
252 	sym->st_name = strtabsz;
253 	sym->st_value = 0;
254 	sym->st_size = dof->dofh_filesz;
255 	sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT);
256 	sym->st_other = ELF32_ST_VISIBILITY(STV_HIDDEN);
257 	sym->st_shndx = ESHDR_DOF;
258 	sym++;
259 
260 	if (dtp->dt_lazyload) {
261 		bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz,
262 		    sizeof (DOFLAZYSTR));
263 		strtabsz += sizeof (DOFLAZYSTR);
264 	} else {
265 		bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR));
266 		strtabsz += sizeof (DOFSTR);
267 	}
268 
269 	assert(count == dep->de_nrel);
270 	assert(strtabsz == dep->de_strlen);
271 
272 	return (0);
273 }
274 
275 
276 typedef struct dof_elf64 {
277 	uint32_t de_nrel;
278 	Elf64_Rela *de_rel;
279 	uint32_t de_nsym;
280 	Elf64_Sym *de_sym;
281 
282 	uint32_t de_strlen;
283 	char *de_strtab;
284 
285 	uint32_t de_global;
286 } dof_elf64_t;
287 
288 static int
289 prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep)
290 {
291 	dof_sec_t *dofs, *s;
292 	dof_relohdr_t *dofrh;
293 	dof_relodesc_t *dofr;
294 	char *strtab;
295 	int i, j, nrel;
296 	size_t strtabsz = 1;
297 	uint64_t count = 0;
298 	size_t base;
299 	Elf64_Sym *sym;
300 	Elf64_Rela *rel;
301 
302 	/*LINTED*/
303 	dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff);
304 
305 	/*
306 	 * First compute the size of the string table and the number of
307 	 * relocations present in the DOF.
308 	 */
309 	for (i = 0; i < dof->dofh_secnum; i++) {
310 		if (dofs[i].dofs_type != DOF_SECT_URELHDR)
311 			continue;
312 
313 		/*LINTED*/
314 		dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset);
315 
316 		s = &dofs[dofrh->dofr_strtab];
317 		strtab = (char *)dof + s->dofs_offset;
318 		assert(strtab[0] == '\0');
319 		strtabsz += s->dofs_size - 1;
320 
321 		s = &dofs[dofrh->dofr_relsec];
322 		/*LINTED*/
323 		dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset);
324 		count += s->dofs_size / s->dofs_entsize;
325 	}
326 
327 	dep->de_strlen = strtabsz;
328 	dep->de_nrel = count;
329 	dep->de_nsym = count + 1; /* the first symbol is always null */
330 
331 	if (dtp->dt_lazyload) {
332 		dep->de_strlen += sizeof (DOFLAZYSTR);
333 		dep->de_nsym++;
334 	} else {
335 		dep->de_strlen += sizeof (DOFSTR);
336 		dep->de_nsym++;
337 	}
338 
339 	if ((dep->de_rel = calloc(dep->de_nrel,
340 	    sizeof (dep->de_rel[0]))) == NULL) {
341 		return (dt_set_errno(dtp, EDT_NOMEM));
342 	}
343 
344 	if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf64_Sym))) == NULL) {
345 		free(dep->de_rel);
346 		return (dt_set_errno(dtp, EDT_NOMEM));
347 	}
348 
349 	if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) {
350 		free(dep->de_rel);
351 		free(dep->de_sym);
352 		return (dt_set_errno(dtp, EDT_NOMEM));
353 	}
354 
355 	count = 0;
356 	strtabsz = 1;
357 	dep->de_strtab[0] = '\0';
358 	rel = dep->de_rel;
359 	sym = dep->de_sym;
360 	dep->de_global = 1;
361 
362 	/*
363 	 * The first symbol table entry must be zeroed and is always ignored.
364 	 */
365 	bzero(sym, sizeof (Elf64_Sym));
366 	sym++;
367 
368 	/*
369 	 * Take a second pass through the DOF sections filling in the
370 	 * memory we allocated.
371 	 */
372 	for (i = 0; i < dof->dofh_secnum; i++) {
373 		if (dofs[i].dofs_type != DOF_SECT_URELHDR)
374 			continue;
375 
376 		/*LINTED*/
377 		dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset);
378 
379 		s = &dofs[dofrh->dofr_strtab];
380 		strtab = (char *)dof + s->dofs_offset;
381 		bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size);
382 		base = strtabsz;
383 		strtabsz += s->dofs_size - 1;
384 
385 		s = &dofs[dofrh->dofr_relsec];
386 		/*LINTED*/
387 		dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset);
388 		nrel = s->dofs_size / s->dofs_entsize;
389 
390 		s = &dofs[dofrh->dofr_tgtsec];
391 
392 		for (j = 0; j < nrel; j++) {
393 #if defined(__aarch64__)
394 			rel->r_offset = s->dofs_offset +
395 			    dofr[j].dofr_offset;
396 			rel->r_info = ELF64_R_INFO(count + dep->de_global,
397 			    R_AARCH64_PREL64);
398 #elif defined(__arm__)
399 /* XXX */
400 #elif defined(__powerpc__)
401 			rel->r_offset = s->dofs_offset +
402 			    dofr[j].dofr_offset;
403 			rel->r_info = ELF64_R_INFO(count + dep->de_global,
404 			    R_PPC64_REL64);
405 #elif defined(__riscv)
406 			rel->r_offset = s->dofs_offset + dofr[j].dofr_offset;
407 			rel->r_info = ELF64_R_INFO(count + dep->de_global,
408 			    R_RISCV_32_PCREL);
409 #elif defined(__i386) || defined(__amd64)
410 			rel->r_offset = s->dofs_offset +
411 			    dofr[j].dofr_offset;
412 			rel->r_info = ELF64_R_INFO(count + dep->de_global,
413 			    R_X86_64_PC64);
414 #else
415 #error unknown ISA
416 #endif
417 
418 			sym->st_name = base + dofr[j].dofr_name - 1;
419 			sym->st_value = 0;
420 			sym->st_size = 0;
421 			sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC);
422 			sym->st_other = ELF64_ST_VISIBILITY(STV_HIDDEN);
423 			sym->st_shndx = SHN_UNDEF;
424 
425 			rel++;
426 			sym++;
427 			count++;
428 		}
429 	}
430 
431 	/*
432 	 * Add a symbol for the DOF itself. We use a different symbol for
433 	 * lazily and actively loaded DOF to make them easy to distinguish.
434 	 */
435 	sym->st_name = strtabsz;
436 	sym->st_value = 0;
437 	sym->st_size = dof->dofh_filesz;
438 	sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
439 	sym->st_other = ELF64_ST_VISIBILITY(STV_HIDDEN);
440 	sym->st_shndx = ESHDR_DOF;
441 	sym++;
442 
443 	if (dtp->dt_lazyload) {
444 		bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz,
445 		    sizeof (DOFLAZYSTR));
446 		strtabsz += sizeof (DOFLAZYSTR);
447 	} else {
448 		bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR));
449 		strtabsz += sizeof (DOFSTR);
450 	}
451 
452 	assert(count == dep->de_nrel);
453 	assert(strtabsz == dep->de_strlen);
454 
455 	return (0);
456 }
457 
458 /*
459  * Write out an ELF32 file prologue consisting of a header, section headers,
460  * and a section header string table.  The DOF data will follow this prologue
461  * and complete the contents of the given ELF file.
462  */
463 static int
464 dump_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd)
465 {
466 	struct {
467 		Elf32_Ehdr ehdr;
468 		Elf32_Shdr shdr[ESHDR_NUM];
469 	} elf_file;
470 
471 	Elf32_Shdr *shp;
472 	Elf32_Off off;
473 	dof_elf32_t de;
474 	int ret = 0;
475 	uint_t nshdr;
476 
477 	if (prepare_elf32(dtp, dof, &de) != 0)
478 		return (-1); /* errno is set for us */
479 
480 	/*
481 	 * If there are no relocations, we only need enough sections for
482 	 * the shstrtab and the DOF.
483 	 */
484 	nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM;
485 
486 	bzero(&elf_file, sizeof (elf_file));
487 
488 	elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0;
489 	elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1;
490 	elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2;
491 	elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3;
492 	elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT;
493 	elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS32;
494 #if BYTE_ORDER == _BIG_ENDIAN
495 	elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
496 #else
497 	elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
498 #endif
499 	elf_file.ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
500 	elf_file.ehdr.e_type = ET_REL;
501 #if defined(__arm__)
502 	elf_file.ehdr.e_machine = EM_ARM;
503 #elif defined(__powerpc__)
504 	elf_file.ehdr.e_machine = EM_PPC;
505 #elif defined(__i386) || defined(__amd64)
506 	elf_file.ehdr.e_machine = EM_386;
507 #elif defined(__aarch64__)
508 	elf_file.ehdr.e_machine = EM_AARCH64;
509 #elif defined(__riscv)
510 	elf_file.ehdr.e_machine = EM_RISCV;
511 
512 	/* Set the ELF flags according to our current ABI */
513 #if defined(__riscv_compressed)
514 	elf_file.ehdr.e_flags |= EF_RISCV_RVC;
515 #endif
516 #if defined(__riscv_float_abi_soft)
517 	elf_file.ehdr.e_flags |= EF_RISCV_FLOAT_ABI_SOFT;
518 #endif
519 #if defined(__riscv_float_abi_single)
520 	elf_file.ehdr.e_flags |= EF_RISCV_FLOAT_ABI_SINGLE;
521 #endif
522 #if defined(__riscv_float_abi_double)
523 	elf_file.ehdr.e_flags |= EF_RISCV_FLOAT_ABI_DOUBLE;
524 #endif
525 #endif
526 	elf_file.ehdr.e_version = EV_CURRENT;
527 	elf_file.ehdr.e_shoff = sizeof (Elf32_Ehdr);
528 	elf_file.ehdr.e_ehsize = sizeof (Elf32_Ehdr);
529 	elf_file.ehdr.e_phentsize = sizeof (Elf32_Phdr);
530 	elf_file.ehdr.e_shentsize = sizeof (Elf32_Shdr);
531 	elf_file.ehdr.e_shnum = nshdr;
532 	elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB;
533 	off = sizeof (elf_file) + nshdr * sizeof (Elf32_Shdr);
534 
535 	shp = &elf_file.shdr[ESHDR_SHSTRTAB];
536 	shp->sh_name = 1; /* DTRACE_SHSTRTAB32[1] = ".shstrtab" */
537 	shp->sh_type = SHT_STRTAB;
538 	shp->sh_offset = off;
539 	shp->sh_size = sizeof (DTRACE_SHSTRTAB32);
540 	shp->sh_addralign = sizeof (char);
541 	off = roundup2(shp->sh_offset + shp->sh_size, 8);
542 
543 	shp = &elf_file.shdr[ESHDR_DOF];
544 	shp->sh_name = 11; /* DTRACE_SHSTRTAB32[11] = ".SUNW_dof" */
545 	shp->sh_flags = SHF_ALLOC;
546 	shp->sh_type = SHT_SUNW_dof;
547 	shp->sh_offset = off;
548 	shp->sh_size = dof->dofh_filesz;
549 	shp->sh_addralign = 8;
550 	off = shp->sh_offset + shp->sh_size;
551 
552 	shp = &elf_file.shdr[ESHDR_STRTAB];
553 	shp->sh_name = 21; /* DTRACE_SHSTRTAB32[21] = ".strtab" */
554 	shp->sh_flags = SHF_ALLOC;
555 	shp->sh_type = SHT_STRTAB;
556 	shp->sh_offset = off;
557 	shp->sh_size = de.de_strlen;
558 	shp->sh_addralign = sizeof (char);
559 	off = roundup2(shp->sh_offset + shp->sh_size, 4);
560 
561 	shp = &elf_file.shdr[ESHDR_SYMTAB];
562 	shp->sh_name = 29; /* DTRACE_SHSTRTAB32[29] = ".symtab" */
563 	shp->sh_flags = SHF_ALLOC;
564 	shp->sh_type = SHT_SYMTAB;
565 	shp->sh_entsize = sizeof (Elf32_Sym);
566 	shp->sh_link = ESHDR_STRTAB;
567 	shp->sh_offset = off;
568 	shp->sh_info = de.de_global;
569 	shp->sh_size = de.de_nsym * sizeof (Elf32_Sym);
570 	shp->sh_addralign = 4;
571 	off = roundup2(shp->sh_offset + shp->sh_size, 4);
572 
573 	if (de.de_nrel == 0) {
574 		if (dt_write(dtp, fd, &elf_file,
575 		    sizeof (elf_file)) != sizeof (elf_file) ||
576 		    PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) ||
577 		    PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) ||
578 		    PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) ||
579 		    PWRITE_SCN(ESHDR_DOF, dof)) {
580 			ret = dt_set_errno(dtp, errno);
581 		}
582 	} else {
583 		shp = &elf_file.shdr[ESHDR_REL];
584 		shp->sh_name = 37; /* DTRACE_SHSTRTAB32[37] = ".rel.SUNW_dof" */
585 		shp->sh_flags = 0;
586 		shp->sh_type = SHT_REL;
587 		shp->sh_entsize = sizeof (de.de_rel[0]);
588 		shp->sh_link = ESHDR_SYMTAB;
589 		shp->sh_info = ESHDR_DOF;
590 		shp->sh_offset = off;
591 		shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]);
592 		shp->sh_addralign = 4;
593 
594 		if (dt_write(dtp, fd, &elf_file,
595 		    sizeof (elf_file)) != sizeof (elf_file) ||
596 		    PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) ||
597 		    PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) ||
598 		    PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) ||
599 		    PWRITE_SCN(ESHDR_REL, de.de_rel) ||
600 		    PWRITE_SCN(ESHDR_DOF, dof)) {
601 			ret = dt_set_errno(dtp, errno);
602 		}
603 	}
604 
605 	free(de.de_strtab);
606 	free(de.de_sym);
607 	free(de.de_rel);
608 
609 	return (ret);
610 }
611 
612 /*
613  * Write out an ELF64 file prologue consisting of a header, section headers,
614  * and a section header string table.  The DOF data will follow this prologue
615  * and complete the contents of the given ELF file.
616  */
617 static int
618 dump_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd)
619 {
620 	struct {
621 		Elf64_Ehdr ehdr;
622 		Elf64_Shdr shdr[ESHDR_NUM];
623 	} elf_file;
624 
625 	Elf64_Shdr *shp;
626 	Elf64_Off off;
627 	dof_elf64_t de;
628 	int ret = 0;
629 	uint_t nshdr;
630 
631 	if (prepare_elf64(dtp, dof, &de) != 0)
632 		return (-1); /* errno is set for us */
633 
634 	/*
635 	 * If there are no relocations, we only need enough sections for
636 	 * the shstrtab and the DOF.
637 	 */
638 	nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM;
639 
640 	bzero(&elf_file, sizeof (elf_file));
641 
642 	elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0;
643 	elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1;
644 	elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2;
645 	elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3;
646 	elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT;
647 	elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS64;
648 #if BYTE_ORDER == _BIG_ENDIAN
649 	elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
650 #else
651 	elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
652 #endif
653 	elf_file.ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
654 	elf_file.ehdr.e_type = ET_REL;
655 #if defined(__arm__)
656 	elf_file.ehdr.e_machine = EM_ARM;
657 #elif defined(__powerpc64__)
658 #if defined(_CALL_ELF) && _CALL_ELF == 2
659 	elf_file.ehdr.e_flags = 2;
660 #endif
661 	elf_file.ehdr.e_machine = EM_PPC64;
662 #elif defined(__i386) || defined(__amd64)
663 	elf_file.ehdr.e_machine = EM_AMD64;
664 #elif defined(__aarch64__)
665 	elf_file.ehdr.e_machine = EM_AARCH64;
666 #elif defined(__riscv)
667 	elf_file.ehdr.e_machine = EM_RISCV;
668 
669 	/* Set the ELF flags according to our current ABI */
670 #if defined(__riscv_compressed)
671 	elf_file.ehdr.e_flags |= EF_RISCV_RVC;
672 #endif
673 #if defined(__riscv_float_abi_soft)
674 	elf_file.ehdr.e_flags |= EF_RISCV_FLOAT_ABI_SOFT;
675 #endif
676 #if defined(__riscv_float_abi_single)
677 	elf_file.ehdr.e_flags |= EF_RISCV_FLOAT_ABI_SINGLE;
678 #endif
679 #if defined(__riscv_float_abi_double)
680 	elf_file.ehdr.e_flags |= EF_RISCV_FLOAT_ABI_DOUBLE;
681 #endif
682 #endif
683 	elf_file.ehdr.e_version = EV_CURRENT;
684 	elf_file.ehdr.e_shoff = sizeof (Elf64_Ehdr);
685 	elf_file.ehdr.e_ehsize = sizeof (Elf64_Ehdr);
686 	elf_file.ehdr.e_phentsize = sizeof (Elf64_Phdr);
687 	elf_file.ehdr.e_shentsize = sizeof (Elf64_Shdr);
688 	elf_file.ehdr.e_shnum = nshdr;
689 	elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB;
690 	off = sizeof (elf_file) + nshdr * sizeof (Elf64_Shdr);
691 
692 	shp = &elf_file.shdr[ESHDR_SHSTRTAB];
693 	shp->sh_name = 1; /* DTRACE_SHSTRTAB64[1] = ".shstrtab" */
694 	shp->sh_type = SHT_STRTAB;
695 	shp->sh_offset = off;
696 	shp->sh_size = sizeof (DTRACE_SHSTRTAB64);
697 	shp->sh_addralign = sizeof (char);
698 	off = roundup2(shp->sh_offset + shp->sh_size, 8);
699 
700 	shp = &elf_file.shdr[ESHDR_DOF];
701 	shp->sh_name = 11; /* DTRACE_SHSTRTAB64[11] = ".SUNW_dof" */
702 	shp->sh_flags = SHF_ALLOC;
703 	shp->sh_type = SHT_SUNW_dof;
704 	shp->sh_offset = off;
705 	shp->sh_size = dof->dofh_filesz;
706 	shp->sh_addralign = 8;
707 	off = shp->sh_offset + shp->sh_size;
708 
709 	shp = &elf_file.shdr[ESHDR_STRTAB];
710 	shp->sh_name = 21; /* DTRACE_SHSTRTAB64[21] = ".strtab" */
711 	shp->sh_flags = SHF_ALLOC;
712 	shp->sh_type = SHT_STRTAB;
713 	shp->sh_offset = off;
714 	shp->sh_size = de.de_strlen;
715 	shp->sh_addralign = sizeof (char);
716 	off = roundup2(shp->sh_offset + shp->sh_size, 8);
717 
718 	shp = &elf_file.shdr[ESHDR_SYMTAB];
719 	shp->sh_name = 29; /* DTRACE_SHSTRTAB64[29] = ".symtab" */
720 	shp->sh_flags = SHF_ALLOC;
721 	shp->sh_type = SHT_SYMTAB;
722 	shp->sh_entsize = sizeof (Elf64_Sym);
723 	shp->sh_link = ESHDR_STRTAB;
724 	shp->sh_offset = off;
725 	shp->sh_info = de.de_global;
726 	shp->sh_size = de.de_nsym * sizeof (Elf64_Sym);
727 	shp->sh_addralign = 8;
728 	off = roundup2(shp->sh_offset + shp->sh_size, 8);
729 
730 	if (de.de_nrel == 0) {
731 		if (dt_write(dtp, fd, &elf_file,
732 		    sizeof (elf_file)) != sizeof (elf_file) ||
733 		    PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) ||
734 		    PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) ||
735 		    PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) ||
736 		    PWRITE_SCN(ESHDR_DOF, dof)) {
737 			ret = dt_set_errno(dtp, errno);
738 		}
739 	} else {
740 		shp = &elf_file.shdr[ESHDR_REL];
741 		shp->sh_name = 37; /* DTRACE_SHSTRTAB64[37] = ".rel.SUNW_dof" */
742 		shp->sh_flags = 0;
743 		shp->sh_type = SHT_RELA;
744 		shp->sh_entsize = sizeof (de.de_rel[0]);
745 		shp->sh_link = ESHDR_SYMTAB;
746 		shp->sh_info = ESHDR_DOF;
747 		shp->sh_offset = off;
748 		shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]);
749 		shp->sh_addralign = 8;
750 
751 		if (dt_write(dtp, fd, &elf_file,
752 		    sizeof (elf_file)) != sizeof (elf_file) ||
753 		    PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) ||
754 		    PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) ||
755 		    PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) ||
756 		    PWRITE_SCN(ESHDR_REL, de.de_rel) ||
757 		    PWRITE_SCN(ESHDR_DOF, dof)) {
758 			ret = dt_set_errno(dtp, errno);
759 		}
760 	}
761 
762 	free(de.de_strtab);
763 	free(de.de_sym);
764 	free(de.de_rel);
765 
766 	return (ret);
767 }
768 
769 static int
770 dt_symtab_lookup(Elf_Data *data_sym, int start, int end, uintptr_t addr,
771     uint_t shn, GElf_Sym *sym, int uses_funcdesc, Elf *elf)
772 {
773 	Elf64_Addr symval;
774 	Elf_Scn *opd_scn;
775 	Elf_Data *opd_desc;
776 	int i;
777 
778 	for (i = start; i < end && gelf_getsym(data_sym, i, sym) != NULL; i++) {
779 		if (GELF_ST_TYPE(sym->st_info) == STT_FUNC) {
780 			symval = sym->st_value;
781 			if (uses_funcdesc) {
782 				opd_scn = elf_getscn(elf, sym->st_shndx);
783 				opd_desc = elf_rawdata(opd_scn, NULL);
784 				symval =
785 				    *(uint64_t*)((char *)opd_desc->d_buf + symval);
786 			}
787 			if ((uses_funcdesc || shn == sym->st_shndx) &&
788 			    symval <= addr && addr < symval + sym->st_size)
789 				return (0);
790 		}
791 	}
792 
793 	return (-1);
794 }
795 
796 #if defined(__aarch64__)
797 #define	DT_OP_NOP		0xd503201f
798 #define	DT_OP_RET		0xd65f03c0
799 #define	DT_OP_CALL26		0x94000000
800 #define	DT_OP_JUMP26		0x14000000
801 #define	DT_REL_NONE		R_AARCH64_NONE
802 
803 static int
804 dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
805     uint32_t *off)
806 {
807 	uint32_t *ip;
808 
809 	/*
810 	 * Ensure that the offset is aligned on an instruction boundary.
811 	 */
812 	if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0)
813 		return (-1);
814 
815 	/*
816 	 * We only know about some specific relocation types.
817 	 * We also recognize relocation type NONE, since that gets used for
818 	 * relocations of USDT probes, and we might be re-processing a file.
819 	 */
820 	if (GELF_R_TYPE(rela->r_info) != R_AARCH64_CALL26 &&
821 	    GELF_R_TYPE(rela->r_info) != R_AARCH64_JUMP26 &&
822 	    GELF_R_TYPE(rela->r_info) != R_AARCH64_NONE)
823 		return (-1);
824 
825 	ip = (uint32_t *)(p + rela->r_offset);
826 
827 	/*
828 	 * We may have already processed this object file in an earlier linker
829 	 * invocation. Check to see if the present instruction sequence matches
830 	 * the one we would install below.
831 	 */
832 	if (ip[0] == DT_OP_NOP || ip[0] == DT_OP_RET)
833 		return (0);
834 
835 	/*
836 	 * We only expect call instructions with a displacement of 0, or a jump
837 	 * instruction acting as a tail call.
838 	 */
839 	if (ip[0] != DT_OP_CALL26 && ip[0] != DT_OP_JUMP26) {
840 		dt_dprintf("found %x instead of a call or jmp instruction at "
841 		    "%llx\n", ip[0], (u_longlong_t)rela->r_offset);
842 		return (-1);
843 	}
844 
845 	/*
846 	 * On arm64, we do not have to differentiate between regular probes and
847 	 * is-enabled probes.  Both cases are encoded as a regular branch for
848 	 * non-tail call locations, and a jump for tail call locations.  Calls
849 	 * are to be converted into a no-op whereas jumps should become a
850 	 * return.
851 	 */
852 	if (ip[0] == DT_OP_CALL26)
853 		ip[0] = DT_OP_NOP;
854 	else
855 		ip[0] = DT_OP_RET;
856 
857 	return (0);
858 }
859 #elif defined(__arm__)
860 #define	DT_REL_NONE		R_ARM_NONE
861 
862 static int
863 dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
864     uint32_t *off)
865 {
866 	printf("%s:%s(%d): arm not implemented\n", __FUNCTION__, __FILE__,
867 	    __LINE__);
868 	return (-1);
869 }
870 #elif defined(__powerpc__)
871 /* The sentinel is 'xor r3,r3,r3'. */
872 #define DT_OP_XOR_R3	0x7c631a78
873 
874 #define DT_OP_NOP		0x60000000
875 #define DT_OP_BLR		0x4e800020
876 
877 /* This captures all forms of branching to address. */
878 #define DT_IS_BRANCH(inst)	((inst & 0xfc000000) == 0x48000000)
879 #define DT_IS_BL(inst)	(DT_IS_BRANCH(inst) && (inst & 0x01))
880 
881 #define	DT_REL_NONE		R_PPC_NONE
882 
883 static int
884 dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
885     uint32_t *off)
886 {
887 	uint32_t *ip;
888 
889 	if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0)
890 		return (-1);
891 
892 	/*LINTED*/
893 	ip = (uint32_t *)(p + rela->r_offset);
894 
895 	/*
896 	 * We only know about some specific relocation types.
897 	 */
898 	if (GELF_R_TYPE(rela->r_info) != R_PPC_REL24 &&
899 	    GELF_R_TYPE(rela->r_info) != R_PPC_PLTREL24 &&
900 	    GELF_R_TYPE(rela->r_info) != R_PPC_NONE)
901 		return (-1);
902 
903 	/*
904 	 * We may have already processed this object file in an earlier linker
905 	 * invocation. Check to see if the present instruction sequence matches
906 	 * the one we would install below.
907 	 */
908 	if (isenabled) {
909 		if (ip[0] == DT_OP_XOR_R3) {
910 			(*off) += sizeof (ip[0]);
911 			return (0);
912 		}
913 	} else {
914 		if (ip[0] == DT_OP_NOP) {
915 			(*off) += sizeof (ip[0]);
916 			return (0);
917 		}
918 	}
919 
920 	/*
921 	 * We only expect branch to address instructions.
922 	 */
923 	if (!DT_IS_BRANCH(ip[0])) {
924 		dt_dprintf("found %x instead of a branch instruction at %llx\n",
925 		    ip[0], (u_longlong_t)rela->r_offset);
926 		return (-1);
927 	}
928 
929 	if (isenabled) {
930 		/*
931 		 * It would necessarily indicate incorrect usage if an is-
932 		 * enabled probe were tail-called so flag that as an error.
933 		 * It's also potentially (very) tricky to handle gracefully,
934 		 * but could be done if this were a desired use scenario.
935 		 */
936 		if (!DT_IS_BL(ip[0])) {
937 			dt_dprintf("tail call to is-enabled probe at %llx\n",
938 			    (u_longlong_t)rela->r_offset);
939 			return (-1);
940 		}
941 
942 		ip[0] = DT_OP_XOR_R3;
943 		(*off) += sizeof (ip[0]);
944 	} else {
945 		if (DT_IS_BL(ip[0]))
946 			ip[0] = DT_OP_NOP;
947 		else
948 			ip[0] = DT_OP_BLR;
949 	}
950 
951 	return (0);
952 }
953 #elif defined(__riscv)
954 #define	DT_OP_NOP		0x00000013 /* addi x0, x0, 0 */
955 #define	DT_OP_RET		0x00008067 /* jalr x0, x1, 0 */
956 #define	DT_OP_IS_AUIPC(op)	(((op) & 0x7f) == 0x17)
957 #define	DT_OP_IS_JALR(op)	(((op) & 0x707f) == 0x67)
958 #define	DT_OP_JALR_CALL		0x000080e7 /* jalr x1, x1, 0 */
959 #define	DT_OP_JALR_TAIL		0x00030067 /* jalr x0, x6, 0 */
960 #define	DT_REL_NONE		R_RISCV_NONE
961 
962 static int
963 dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
964     uint32_t *off)
965 {
966 	uint32_t *ip;
967 
968 	/*
969 	 * XXX: this implementation is untested, but should serve as a decent
970 	 * starting point.
971 	 */
972 
973 	/*
974 	 * Ensure that the offset is aligned on a compressed-instruction
975 	 * boundary.
976 	 */
977 	if ((rela->r_offset & (sizeof (uint16_t) - 1)) != 0)
978 		return (-1);
979 
980 	/*
981 	 * We only know about some specific relocation types.
982 	 * We also recognize relocation type NONE, since that gets used for
983 	 * relocations of USDT probes, and we might be re-processing a file.
984 	 */
985 	if (GELF_R_TYPE(rela->r_info) != R_RISCV_CALL &&
986 	    GELF_R_TYPE(rela->r_info) != R_RISCV_CALL_PLT &&
987 	    GELF_R_TYPE(rela->r_info) != R_RISCV_NONE)
988 		return (-1);
989 
990 	ip = (uint32_t *)(p + rela->r_offset);
991 
992 	/*
993 	 * We may have already processed this object file in an earlier linker
994 	 * invocation. Check to see if the present instruction sequence matches
995 	 * the one we would install below.
996 	 */
997 	if (ip[0] == DT_OP_NOP && (ip[1] == DT_OP_NOP || ip[1] == DT_OP_RET))
998 		return (0);
999 
1000 	/*
1001 	 * We expect a auipc+jalr pair, either from a call or a tail.
1002 	 *  - call: auipc x1 0; jalr x1, x1, 0
1003 	 *  - tail: auipc x6 0; jalr x0, x6, 0
1004 	 */
1005 	if (!DT_OP_IS_AUIPC(ip[0]) || !DT_OP_IS_JALR(ip[1]))
1006 		return (-1);
1007 
1008 	/*
1009 	 * On riscv, we do not have to differentiate between regular probes and
1010 	 * is-enabled probes. Calls are to be converted into a no-op whereas
1011 	 * tail calls should become a return.
1012 	 */
1013 	if (ip[1] == DT_OP_JALR_CALL) {
1014 		ip[0] = DT_OP_NOP;
1015 		ip[1] = DT_OP_NOP;
1016 	} else {
1017 		ip[0] = DT_OP_NOP;
1018 		ip[1] = DT_OP_RET;
1019 	}
1020 
1021 	return (0);
1022 }
1023 
1024 #elif defined(__i386) || defined(__amd64)
1025 
1026 #define	DT_OP_NOP		0x90
1027 #define	DT_OP_RET		0xc3
1028 #define	DT_OP_CALL		0xe8
1029 #define	DT_OP_JMP32		0xe9
1030 #define	DT_OP_REX_RAX		0x48
1031 #define	DT_OP_XOR_EAX_0		0x33
1032 #define	DT_OP_XOR_EAX_1		0xc0
1033 
1034 #define	DT_REL_NONE		R_386_NONE
1035 
1036 static int
1037 dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
1038     uint32_t *off)
1039 {
1040 	uint8_t *ip = (uint8_t *)(p + rela->r_offset - 1);
1041 	uint8_t ret;
1042 
1043 	/*
1044 	 * On x86, the first byte of the instruction is the call opcode and
1045 	 * the next four bytes are the 32-bit address; the relocation is for
1046 	 * the address operand. We back up the offset to the first byte of
1047 	 * the instruction. For is-enabled probes, we later advance the offset
1048 	 * so that it hits the first nop in the instruction sequence.
1049 	 */
1050 	(*off) -= 1;
1051 
1052 	/*
1053 	 * We only know about some specific relocation types. Luckily
1054 	 * these types have the same values on both 32-bit and 64-bit
1055 	 * x86 architectures.
1056 	 */
1057 	if (GELF_R_TYPE(rela->r_info) != R_386_PC32 &&
1058 	    GELF_R_TYPE(rela->r_info) != R_386_PLT32 &&
1059 	    GELF_R_TYPE(rela->r_info) != R_386_NONE)
1060 		return (-1);
1061 
1062 	/*
1063 	 * We may have already processed this object file in an earlier linker
1064 	 * invocation. Check to see if the present instruction sequence matches
1065 	 * the one we would install. For is-enabled probes, we advance the
1066 	 * offset to the first nop instruction in the sequence to match the
1067 	 * text modification code below.
1068 	 */
1069 	if (!isenabled) {
1070 		if ((ip[0] == DT_OP_NOP || ip[0] == DT_OP_RET) &&
1071 		    ip[1] == DT_OP_NOP && ip[2] == DT_OP_NOP &&
1072 		    ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP)
1073 			return (0);
1074 	} else if (dtp->dt_oflags & DTRACE_O_LP64) {
1075 		if (ip[0] == DT_OP_REX_RAX &&
1076 		    ip[1] == DT_OP_XOR_EAX_0 && ip[2] == DT_OP_XOR_EAX_1 &&
1077 		    (ip[3] == DT_OP_NOP || ip[3] == DT_OP_RET) &&
1078 		    ip[4] == DT_OP_NOP) {
1079 			(*off) += 3;
1080 			return (0);
1081 		}
1082 	} else {
1083 		if (ip[0] == DT_OP_XOR_EAX_0 && ip[1] == DT_OP_XOR_EAX_1 &&
1084 		    (ip[2] == DT_OP_NOP || ip[2] == DT_OP_RET) &&
1085 		    ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) {
1086 			(*off) += 2;
1087 			return (0);
1088 		}
1089 	}
1090 
1091 	/*
1092 	 * We expect either a call instrution with a 32-bit displacement or a
1093 	 * jmp instruction with a 32-bit displacement acting as a tail-call.
1094 	 */
1095 	if (ip[0] != DT_OP_CALL && ip[0] != DT_OP_JMP32) {
1096 		dt_dprintf("found %x instead of a call or jmp instruction at "
1097 		    "%llx\n", ip[0], (u_longlong_t)rela->r_offset);
1098 		return (-1);
1099 	}
1100 
1101 	ret = (ip[0] == DT_OP_JMP32) ? DT_OP_RET : DT_OP_NOP;
1102 
1103 	/*
1104 	 * Establish the instruction sequence -- all nops for probes, and an
1105 	 * instruction to clear the return value register (%eax/%rax) followed
1106 	 * by nops for is-enabled probes. For is-enabled probes, we advance
1107 	 * the offset to the first nop. This isn't stricly necessary but makes
1108 	 * for more readable disassembly when the probe is enabled.
1109 	 */
1110 	if (!isenabled) {
1111 		ip[0] = ret;
1112 		ip[1] = DT_OP_NOP;
1113 		ip[2] = DT_OP_NOP;
1114 		ip[3] = DT_OP_NOP;
1115 		ip[4] = DT_OP_NOP;
1116 	} else if (dtp->dt_oflags & DTRACE_O_LP64) {
1117 		ip[0] = DT_OP_REX_RAX;
1118 		ip[1] = DT_OP_XOR_EAX_0;
1119 		ip[2] = DT_OP_XOR_EAX_1;
1120 		ip[3] = ret;
1121 		ip[4] = DT_OP_NOP;
1122 		(*off) += 3;
1123 	} else {
1124 		ip[0] = DT_OP_XOR_EAX_0;
1125 		ip[1] = DT_OP_XOR_EAX_1;
1126 		ip[2] = ret;
1127 		ip[3] = DT_OP_NOP;
1128 		ip[4] = DT_OP_NOP;
1129 		(*off) += 2;
1130 	}
1131 
1132 	return (0);
1133 }
1134 
1135 #else
1136 #error unknown ISA
1137 #endif
1138 
1139 /*PRINTFLIKE5*/
1140 static int
1141 dt_link_error(dtrace_hdl_t *dtp, Elf *elf, int fd, dt_link_pair_t *bufs,
1142     const char *format, ...)
1143 {
1144 	va_list ap;
1145 	dt_link_pair_t *pair;
1146 
1147 	va_start(ap, format);
1148 	dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap);
1149 	va_end(ap);
1150 
1151 	if (elf != NULL)
1152 		(void) elf_end(elf);
1153 
1154 	if (fd >= 0)
1155 		(void) close(fd);
1156 
1157 	while ((pair = bufs) != NULL) {
1158 		bufs = pair->dlp_next;
1159 		dt_free(dtp, pair->dlp_str);
1160 		dt_free(dtp, pair->dlp_sym);
1161 		dt_free(dtp, pair);
1162 	}
1163 
1164 	return (dt_set_errno(dtp, EDT_COMPILER));
1165 }
1166 
1167 /*
1168  * Provide a unique identifier used when adding global symbols to an object.
1169  * This is the FNV-1a hash of an absolute path for the file.
1170  */
1171 static unsigned int
1172 hash_obj(const char *obj, int fd)
1173 {
1174 	char path[PATH_MAX];
1175 	unsigned int h;
1176 
1177 	if (realpath(obj, path) == NULL)
1178 		return (-1);
1179 
1180 	for (h = 2166136261u, obj = &path[0]; *obj != '\0'; obj++)
1181 		h = (h ^ *obj) * 16777619;
1182 	h &= 0x7fffffff;
1183 	return (h);
1184 }
1185 
1186 static int
1187 process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
1188 {
1189 	static const char dt_prefix[] = "__dtrace";
1190 	static const char dt_enabled[] = "enabled";
1191 	static const char dt_symprefix[] = "$dtrace";
1192 	static const char dt_symfmt[] = "%s%u.%s";
1193 	static const char dt_weaksymfmt[] = "%s.%s";
1194 	char probename[DTRACE_NAMELEN];
1195 	int fd, i, ndx, eprobe, uses_funcdesc = 0, mod = 0;
1196 	Elf *elf = NULL;
1197 	GElf_Ehdr ehdr;
1198 	Elf_Scn *scn_rel, *scn_sym, *scn_str, *scn_tgt;
1199 	Elf_Data *data_rel, *data_sym, *data_str, *data_tgt;
1200 	GElf_Shdr shdr_rel, shdr_sym, shdr_str, shdr_tgt;
1201 	GElf_Sym rsym, fsym, dsym;
1202 	GElf_Rela rela;
1203 	char *s, *p, *r;
1204 	char pname[DTRACE_PROVNAMELEN];
1205 	dt_provider_t *pvp;
1206 	dt_probe_t *prp;
1207 	uint32_t off, eclass, emachine1, emachine2;
1208 	size_t symsize, osym, nsym, isym, istr, len;
1209 	unsigned int objkey;
1210 	dt_link_pair_t *pair, *bufs = NULL;
1211 	dt_strtab_t *strtab;
1212 	void *tmp;
1213 
1214 	if ((fd = open64(obj, O_RDWR)) == -1) {
1215 		return (dt_link_error(dtp, elf, fd, bufs,
1216 		    "failed to open %s: %s", obj, strerror(errno)));
1217 	}
1218 
1219 	if ((elf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL) {
1220 		return (dt_link_error(dtp, elf, fd, bufs,
1221 		    "failed to process %s: %s", obj, elf_errmsg(elf_errno())));
1222 	}
1223 
1224 	switch (elf_kind(elf)) {
1225 	case ELF_K_ELF:
1226 		break;
1227 	case ELF_K_AR:
1228 		return (dt_link_error(dtp, elf, fd, bufs, "archives are not "
1229 		    "permitted; use the contents of the archive instead: %s",
1230 		    obj));
1231 	default:
1232 		return (dt_link_error(dtp, elf, fd, bufs,
1233 		    "invalid file type: %s", obj));
1234 	}
1235 
1236 	if (gelf_getehdr(elf, &ehdr) == NULL) {
1237 		return (dt_link_error(dtp, elf, fd, bufs, "corrupt file: %s",
1238 		    obj));
1239 	}
1240 
1241 	if (dtp->dt_oflags & DTRACE_O_LP64) {
1242 		eclass = ELFCLASS64;
1243 #if defined(__powerpc__)
1244 		emachine1 = emachine2 = EM_PPC64;
1245 #if !defined(_CALL_ELF) || _CALL_ELF == 1
1246 		uses_funcdesc = 1;
1247 #endif
1248 #elif defined(__i386) || defined(__amd64)
1249 		emachine1 = emachine2 = EM_AMD64;
1250 #elif defined(__aarch64__)
1251 		emachine1 = emachine2 = EM_AARCH64;
1252 #elif defined(__riscv)
1253 		emachine1 = emachine2 = EM_RISCV;
1254 #endif
1255 		symsize = sizeof (Elf64_Sym);
1256 	} else {
1257 		eclass = ELFCLASS32;
1258 #if defined(__arm__)
1259 		emachine1 = emachine2 = EM_ARM;
1260 #elif defined(__powerpc__)
1261 		emachine1 = emachine2 = EM_PPC;
1262 #elif defined(__i386) || defined(__amd64)
1263 		emachine1 = emachine2 = EM_386;
1264 #endif
1265 		symsize = sizeof (Elf32_Sym);
1266 	}
1267 
1268 	if (ehdr.e_ident[EI_CLASS] != eclass) {
1269 		return (dt_link_error(dtp, elf, fd, bufs,
1270 		    "incorrect ELF class for object file: %s", obj));
1271 	}
1272 
1273 	if (ehdr.e_machine != emachine1 && ehdr.e_machine != emachine2) {
1274 		return (dt_link_error(dtp, elf, fd, bufs,
1275 		    "incorrect ELF machine type for object file: %s", obj));
1276 	}
1277 
1278 	/*
1279 	 * We use this token as a relatively unique handle for this file on the
1280 	 * system in order to disambiguate potential conflicts between files of
1281 	 * the same name which contain identially named local symbols.
1282 	 */
1283 	if ((objkey = hash_obj(obj, fd)) == (unsigned int)-1)
1284 		return (dt_link_error(dtp, elf, fd, bufs,
1285 		    "failed to generate unique key for object file: %s", obj));
1286 
1287 	scn_rel = NULL;
1288 	while ((scn_rel = elf_nextscn(elf, scn_rel)) != NULL) {
1289 		if (gelf_getshdr(scn_rel, &shdr_rel) == NULL)
1290 			goto err;
1291 
1292 		/*
1293 		 * Skip any non-relocation sections.
1294 		 */
1295 		if (shdr_rel.sh_type != SHT_RELA && shdr_rel.sh_type != SHT_REL)
1296 			continue;
1297 
1298 		if ((data_rel = elf_getdata(scn_rel, NULL)) == NULL)
1299 			goto err;
1300 
1301 		/*
1302 		 * Grab the section, section header and section data for the
1303 		 * symbol table that this relocation section references.
1304 		 */
1305 		if ((scn_sym = elf_getscn(elf, shdr_rel.sh_link)) == NULL ||
1306 		    gelf_getshdr(scn_sym, &shdr_sym) == NULL ||
1307 		    (data_sym = elf_getdata(scn_sym, NULL)) == NULL)
1308 			goto err;
1309 
1310 		/*
1311 		 * Ditto for that symbol table's string table.
1312 		 */
1313 		if ((scn_str = elf_getscn(elf, shdr_sym.sh_link)) == NULL ||
1314 		    gelf_getshdr(scn_str, &shdr_str) == NULL ||
1315 		    (data_str = elf_getdata(scn_str, NULL)) == NULL)
1316 			goto err;
1317 
1318 		/*
1319 		 * Grab the section, section header and section data for the
1320 		 * target section for the relocations. For the relocations
1321 		 * we're looking for -- this will typically be the text of the
1322 		 * object file.
1323 		 */
1324 		if ((scn_tgt = elf_getscn(elf, shdr_rel.sh_info)) == NULL ||
1325 		    gelf_getshdr(scn_tgt, &shdr_tgt) == NULL ||
1326 		    (data_tgt = elf_getdata(scn_tgt, NULL)) == NULL)
1327 			goto err;
1328 
1329 		/*
1330 		 * We're looking for relocations to symbols matching this form:
1331 		 *
1332 		 *   __dtrace[enabled]_<prov>___<probe>
1333 		 *
1334 		 * For the generated object, we need to record the location
1335 		 * identified by the relocation, and create a new relocation
1336 		 * in the generated object that will be resolved at link time
1337 		 * to the location of the function in which the probe is
1338 		 * embedded. In the target object, we change the matched symbol
1339 		 * so that it will be ignored at link time, and we modify the
1340 		 * target (text) section to replace the call instruction with
1341 		 * one or more nops.
1342 		 *
1343 		 * To avoid runtime overhead, the relocations added to the
1344 		 * generated object should be resolved at static link time. We
1345 		 * therefore create aliases for the functions that contain
1346 		 * probes. An alias is global (so that the relocation from the
1347 		 * generated object can be resolved), and hidden (so that its
1348 		 * address is known at static link time). Such aliases have this
1349 		 * form:
1350 		 *
1351 		 *   $dtrace<key>.<function>
1352 		 *
1353 		 * We take a first pass through all the relocations to
1354 		 * populate our string table and count the number of extra
1355 		 * symbols we'll require.
1356 		 *
1357 		 * We also handle the case where the object has already been
1358 		 * processed, to support incremental rebuilds.  Relocations
1359 		 * of interest are converted to type NONE, but all information
1360 		 * needed to reconstruct the output DOF is retained.
1361 		 */
1362 		strtab = dt_strtab_create(1);
1363 		nsym = 0;
1364 		isym = data_sym->d_size / symsize;
1365 		istr = data_str->d_size;
1366 
1367 		for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) {
1368 			if (shdr_rel.sh_type == SHT_RELA) {
1369 				if (gelf_getrela(data_rel, i, &rela) == NULL)
1370 					continue;
1371 			} else {
1372 				GElf_Rel rel;
1373 				if (gelf_getrel(data_rel, i, &rel) == NULL)
1374 					continue;
1375 				rela.r_offset = rel.r_offset;
1376 				rela.r_info = rel.r_info;
1377 				rela.r_addend = 0;
1378 			}
1379 
1380 			if (gelf_getsym(data_sym, GELF_R_SYM(rela.r_info),
1381 			    &rsym) == NULL) {
1382 				dt_strtab_destroy(strtab);
1383 				goto err;
1384 			}
1385 
1386 			s = (char *)data_str->d_buf + rsym.st_name;
1387 
1388 			if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0)
1389 				continue;
1390 
1391 			if (dt_symtab_lookup(data_sym, 0, isym, rela.r_offset,
1392 			    shdr_rel.sh_info, &fsym, uses_funcdesc,
1393 			    elf) != 0) {
1394 				dt_strtab_destroy(strtab);
1395 				goto err;
1396 			}
1397 
1398 			if (fsym.st_name > data_str->d_size) {
1399 				dt_strtab_destroy(strtab);
1400 				goto err;
1401 			}
1402 
1403 			s = (char *)data_str->d_buf + fsym.st_name;
1404 
1405 			/*
1406 			 * If this symbol isn't of type function, we've really
1407 			 * driven off the rails or the object file is corrupt.
1408 			 */
1409 			if (GELF_ST_TYPE(fsym.st_info) != STT_FUNC) {
1410 				dt_strtab_destroy(strtab);
1411 				return (dt_link_error(dtp, elf, fd, bufs,
1412 				    "expected %s to be of type function", s));
1413 			}
1414 
1415 			/*
1416 			 * Aliases of weak symbols don't get a uniquifier.
1417 			 */
1418 			if (GELF_ST_BIND(fsym.st_info) == STB_WEAK) {
1419 				len = snprintf(NULL, 0, dt_weaksymfmt,
1420 				    dt_symprefix, s) + 1;
1421 			} else {
1422 				len = snprintf(NULL, 0, dt_symfmt, dt_symprefix,
1423 				    objkey, s) + 1;
1424 			}
1425 			if ((p = dt_alloc(dtp, len)) == NULL) {
1426 				dt_strtab_destroy(strtab);
1427 				goto err;
1428 			}
1429 			if (GELF_ST_BIND(fsym.st_info) == STB_WEAK) {
1430 				(void) snprintf(p, len, dt_weaksymfmt,
1431 				    dt_symprefix, s);
1432 			} else {
1433 				(void) snprintf(p, len, dt_symfmt, dt_symprefix,
1434 				    objkey, s);
1435 			}
1436 
1437 			if (dt_strtab_index(strtab, p) == -1) {
1438 				/*
1439 				 * Do not add new symbols if this object file
1440 				 * has already been processed.
1441 				 */
1442 				if (GELF_R_TYPE(rela.r_info) != DT_REL_NONE)
1443 					nsym++;
1444 				(void) dt_strtab_insert(strtab, p);
1445 			}
1446 
1447 			dt_free(dtp, p);
1448 		}
1449 
1450 		/*
1451 		 * If any new probes were found, allocate the additional space
1452 		 * for the symbol table and string table, copying the old data
1453 		 * into the new buffers, and marking the buffers as dirty. We
1454 		 * inject those newly allocated buffers into the libelf data
1455 		 * structures, but are still responsible for freeing them once
1456 		 * we're done with the elf handle.
1457 		 */
1458 		osym = isym;
1459 		if (nsym > 0) {
1460 			/*
1461 			 * The first byte of the string table is reserved for
1462 			 * the \0 entry.
1463 			 */
1464 			len = dt_strtab_size(strtab) - 1;
1465 
1466 			assert(len > 0);
1467 			assert(dt_strtab_index(strtab, "") == 0);
1468 
1469 			dt_strtab_destroy(strtab);
1470 
1471 			if ((pair = dt_alloc(dtp, sizeof (*pair))) == NULL)
1472 				goto err;
1473 
1474 			if ((pair->dlp_str = dt_alloc(dtp, data_str->d_size +
1475 			    len)) == NULL) {
1476 				dt_free(dtp, pair);
1477 				goto err;
1478 			}
1479 
1480 			if ((pair->dlp_sym = dt_alloc(dtp, data_sym->d_size +
1481 			    nsym * symsize)) == NULL) {
1482 				dt_free(dtp, pair->dlp_str);
1483 				dt_free(dtp, pair);
1484 				goto err;
1485 			}
1486 
1487 			pair->dlp_next = bufs;
1488 			bufs = pair;
1489 
1490 			bcopy(data_str->d_buf, pair->dlp_str, data_str->d_size);
1491 			tmp = data_str->d_buf;
1492 			data_str->d_buf = pair->dlp_str;
1493 			pair->dlp_str = tmp;
1494 			data_str->d_size += len;
1495 			(void) elf_flagdata(data_str, ELF_C_SET, ELF_F_DIRTY);
1496 
1497 			shdr_str.sh_size += len;
1498 			(void) gelf_update_shdr(scn_str, &shdr_str);
1499 
1500 			bcopy(data_sym->d_buf, pair->dlp_sym, data_sym->d_size);
1501 			tmp = data_sym->d_buf;
1502 			data_sym->d_buf = pair->dlp_sym;
1503 			pair->dlp_sym = tmp;
1504 			data_sym->d_size += nsym * symsize;
1505 			(void) elf_flagdata(data_sym, ELF_C_SET, ELF_F_DIRTY);
1506 
1507 			shdr_sym.sh_size += nsym * symsize;
1508 			(void) gelf_update_shdr(scn_sym, &shdr_sym);
1509 
1510 			nsym += isym;
1511 		} else if (dt_strtab_empty(strtab)) {
1512 			dt_strtab_destroy(strtab);
1513 			continue;
1514 		}
1515 
1516 		/*
1517 		 * Now that the tables have been allocated, perform the
1518 		 * modifications described above.
1519 		 */
1520 		for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) {
1521 			if (shdr_rel.sh_type == SHT_RELA) {
1522 				if (gelf_getrela(data_rel, i, &rela) == NULL)
1523 					continue;
1524 			} else {
1525 				GElf_Rel rel;
1526 				if (gelf_getrel(data_rel, i, &rel) == NULL)
1527 					continue;
1528 				rela.r_offset = rel.r_offset;
1529 				rela.r_info = rel.r_info;
1530 				rela.r_addend = 0;
1531 			}
1532 
1533 			ndx = GELF_R_SYM(rela.r_info);
1534 
1535 			if (gelf_getsym(data_sym, ndx, &rsym) == NULL ||
1536 			    rsym.st_name > data_str->d_size)
1537 				goto err;
1538 
1539 			s = (char *)data_str->d_buf + rsym.st_name;
1540 
1541 			if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0)
1542 				continue;
1543 
1544 			s += sizeof (dt_prefix) - 1;
1545 
1546 			/*
1547 			 * Check to see if this is an 'is-enabled' check as
1548 			 * opposed to a normal probe.
1549 			 */
1550 			if (strncmp(s, dt_enabled,
1551 			    sizeof (dt_enabled) - 1) == 0) {
1552 				s += sizeof (dt_enabled) - 1;
1553 				eprobe = 1;
1554 				*eprobesp = 1;
1555 				dt_dprintf("is-enabled probe\n");
1556 			} else {
1557 				eprobe = 0;
1558 				dt_dprintf("normal probe\n");
1559 			}
1560 
1561 			if (*s++ != '_')
1562 				goto err;
1563 
1564 			if ((p = strstr(s, "___")) == NULL ||
1565 			    p - s >= sizeof (pname))
1566 				goto err;
1567 
1568 			bcopy(s, pname, p - s);
1569 			pname[p - s] = '\0';
1570 
1571 			if (dt_symtab_lookup(data_sym, osym, isym,
1572 			    rela.r_offset, shdr_rel.sh_info, &fsym,
1573 			    uses_funcdesc, elf) == 0) {
1574 				if (fsym.st_name > data_str->d_size)
1575 					goto err;
1576 
1577 				r = s = (char *) data_str->d_buf + fsym.st_name;
1578 				assert(strstr(s, dt_symprefix) == s);
1579 				s = strchr(s, '.') + 1;
1580 			} else if (dt_symtab_lookup(data_sym, 0, osym,
1581 			    rela.r_offset, shdr_rel.sh_info, &fsym,
1582 			    uses_funcdesc, elf) == 0) {
1583 				u_int bind;
1584 
1585 				bind = GELF_ST_BIND(fsym.st_info) == STB_WEAK ?
1586 				    STB_WEAK : STB_GLOBAL;
1587 				s = (char *) data_str->d_buf + fsym.st_name;
1588 				if (GELF_R_TYPE(rela.r_info) != DT_REL_NONE) {
1589 					/*
1590 					 * Emit an alias for the symbol. It
1591 					 * needs to be non-preemptible so that
1592 					 * .SUNW_dof relocations may be resolved
1593 					 * at static link time. Aliases of weak
1594 					 * symbols are given a non-unique name
1595 					 * so that they may be merged by the
1596 					 * linker.
1597 					 */
1598 					dsym = fsym;
1599 					dsym.st_name = istr;
1600 					dsym.st_info = GELF_ST_INFO(bind,
1601 					    STT_FUNC);
1602 					dsym.st_other =
1603 					    GELF_ST_VISIBILITY(STV_HIDDEN);
1604 					(void) gelf_update_sym(data_sym, isym,
1605 					    &dsym);
1606 					isym++;
1607 					assert(isym <= nsym);
1608 
1609 					r = (char *) data_str->d_buf + istr;
1610 					if (bind == STB_WEAK) {
1611 						istr += sprintf(r,
1612 						    dt_weaksymfmt, dt_symprefix,
1613 						    s);
1614 					} else {
1615 						istr += sprintf(r, dt_symfmt,
1616 						    dt_symprefix, objkey, s);
1617 					}
1618 					istr++;
1619 				} else {
1620 					if (bind == STB_WEAK) {
1621 						(void) asprintf(&r,
1622 						    dt_weaksymfmt, dt_symprefix,
1623 						    s);
1624 					} else {
1625 						(void) asprintf(&r, dt_symfmt,
1626 						    dt_symprefix, objkey, s);
1627 					}
1628 				}
1629 			} else {
1630 				goto err;
1631 			}
1632 
1633 			if ((pvp = dt_provider_lookup(dtp, pname)) == NULL) {
1634 				return (dt_link_error(dtp, elf, fd, bufs,
1635 				    "no such provider %s", pname));
1636 			}
1637 
1638 			if (strlcpy(probename, p + 3, sizeof (probename)) >=
1639 			    sizeof (probename))
1640 				return (dt_link_error(dtp, elf, fd, bufs,
1641 				    "invalid probe name %s", probename));
1642 			(void) strhyphenate(probename);
1643 			if ((prp = dt_probe_lookup(pvp, probename)) == NULL)
1644 				return (dt_link_error(dtp, elf, fd, bufs,
1645 				    "no such probe %s", probename));
1646 
1647 			assert(fsym.st_value <= rela.r_offset);
1648 
1649 			off = rela.r_offset - fsym.st_value;
1650 			if (dt_modtext(dtp, data_tgt->d_buf, eprobe,
1651 			    &rela, &off) != 0)
1652 				goto err;
1653 
1654 			if (dt_probe_define(pvp, prp, s, r, off, eprobe) != 0) {
1655 				return (dt_link_error(dtp, elf, fd, bufs,
1656 				    "failed to allocate space for probe"));
1657 			}
1658 
1659 			/*
1660 			 * We are done with this relocation, but it must be
1661 			 * preserved in order to support incremental rebuilds.
1662 			 */
1663 			if (shdr_rel.sh_type == SHT_RELA) {
1664 				rela.r_info = GELF_R_INFO(
1665 				    GELF_R_SYM(rela.r_info), DT_REL_NONE);
1666 				(void) gelf_update_rela(data_rel, i, &rela);
1667 			} else {
1668 				GElf_Rel rel;
1669 				rel.r_offset = rela.r_offset;
1670 				rel.r_info = GELF_R_INFO(
1671 				    GELF_R_SYM(rela.r_info), DT_REL_NONE);
1672 				(void) gelf_update_rel(data_rel, i, &rel);
1673 			}
1674 
1675 			mod = 1;
1676 			(void) elf_flagdata(data_tgt, ELF_C_SET, ELF_F_DIRTY);
1677 
1678 			/*
1679 			 * This symbol may already have been marked to
1680 			 * be ignored by another relocation referencing
1681 			 * the same symbol or if this object file has
1682 			 * already been processed by an earlier link
1683 			 * invocation.
1684 			 */
1685 			if (rsym.st_shndx != SHN_ABS) {
1686 				rsym.st_info = GELF_ST_INFO(STB_WEAK, STT_FUNC);
1687 				rsym.st_shndx = SHN_ABS;
1688 				(void) gelf_update_sym(data_sym, ndx, &rsym);
1689 			}
1690 		}
1691 	}
1692 
1693 	if (mod && elf_update(elf, ELF_C_WRITE) == -1)
1694 		goto err;
1695 
1696 	(void) elf_end(elf);
1697 	(void) close(fd);
1698 
1699 	while ((pair = bufs) != NULL) {
1700 		bufs = pair->dlp_next;
1701 		dt_free(dtp, pair->dlp_str);
1702 		dt_free(dtp, pair->dlp_sym);
1703 		dt_free(dtp, pair);
1704 	}
1705 
1706 	return (0);
1707 
1708 err:
1709 	return (dt_link_error(dtp, elf, fd, bufs,
1710 	    "an error was encountered while processing %s", obj));
1711 }
1712 
1713 int
1714 dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
1715     const char *file, int objc, char *const objv[])
1716 {
1717 	char tfile[PATH_MAX];
1718 	char drti[PATH_MAX];
1719 	dof_hdr_t *dof;
1720 	int fd, status, i, cur;
1721 	char *cmd, tmp;
1722 	size_t len;
1723 	int eprobes = 0, ret = 0;
1724 
1725 	/*
1726 	 * A NULL program indicates a special use in which we just link
1727 	 * together a bunch of object files specified in objv and then
1728 	 * unlink(2) those object files.
1729 	 */
1730 	if (pgp == NULL) {
1731 		const char *fmt = "%s -o %s -r";
1732 
1733 		len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file) + 1;
1734 
1735 		for (i = 0; i < objc; i++)
1736 			len += strlen(objv[i]) + 1;
1737 
1738 		cmd = alloca(len);
1739 
1740 		cur = snprintf(cmd, len, fmt, dtp->dt_ld_path, file);
1741 
1742 		for (i = 0; i < objc; i++)
1743 			cur += snprintf(cmd + cur, len - cur, " %s", objv[i]);
1744 
1745 		if ((status = system(cmd)) == -1) {
1746 			return (dt_link_error(dtp, NULL, -1, NULL,
1747 			    "failed to run %s: %s", dtp->dt_ld_path,
1748 			    strerror(errno)));
1749 		}
1750 
1751 		if (WIFSIGNALED(status)) {
1752 			return (dt_link_error(dtp, NULL, -1, NULL,
1753 			    "failed to link %s: %s failed due to signal %d",
1754 			    file, dtp->dt_ld_path, WTERMSIG(status)));
1755 		}
1756 
1757 		if (WEXITSTATUS(status) != 0) {
1758 			return (dt_link_error(dtp, NULL, -1, NULL,
1759 			    "failed to link %s: %s exited with status %d\n",
1760 			    file, dtp->dt_ld_path, WEXITSTATUS(status)));
1761 		}
1762 
1763 		for (i = 0; i < objc; i++) {
1764 			if (strcmp(objv[i], file) != 0)
1765 				(void) unlink(objv[i]);
1766 		}
1767 
1768 		return (0);
1769 	}
1770 
1771 	for (i = 0; i < objc; i++) {
1772 		if (process_obj(dtp, objv[i], &eprobes) != 0)
1773 			return (-1); /* errno is set for us */
1774 	}
1775 
1776 	/*
1777 	 * If there are is-enabled probes then we need to force use of DOF
1778 	 * version 2.
1779 	 */
1780 	if (eprobes && pgp->dp_dofversion < DOF_VERSION_2)
1781 		pgp->dp_dofversion = DOF_VERSION_2;
1782 
1783 	if ((dof = dtrace_dof_create(dtp, pgp, dflags)) == NULL)
1784 		return (-1); /* errno is set for us */
1785 
1786 	snprintf(tfile, sizeof(tfile), "%s.XXXXXX", file);
1787 	if ((fd = mkostemp(tfile, O_CLOEXEC)) == -1)
1788 		return (dt_link_error(dtp, NULL, -1, NULL,
1789 		    "failed to create temporary file %s: %s",
1790 		    tfile, strerror(errno)));
1791 
1792 	/*
1793 	 * If -xlinktype=DOF has been selected, just write out the DOF.
1794 	 * Otherwise proceed to the default of generating and linking ELF.
1795 	 */
1796 	switch (dtp->dt_linktype) {
1797 	case DT_LTYP_DOF:
1798 		if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz)
1799 			ret = errno;
1800 
1801 		if (close(fd) != 0 && ret == 0)
1802 			ret = errno;
1803 
1804 		if (ret != 0) {
1805 			return (dt_link_error(dtp, NULL, -1, NULL,
1806 			    "failed to write %s: %s", file, strerror(ret)));
1807 		}
1808 
1809 		return (0);
1810 
1811 	case DT_LTYP_ELF:
1812 		break; /* fall through to the rest of dtrace_program_link() */
1813 
1814 	default:
1815 		return (dt_link_error(dtp, NULL, -1, NULL,
1816 		    "invalid link type %u\n", dtp->dt_linktype));
1817 	}
1818 
1819 
1820 	if (dtp->dt_oflags & DTRACE_O_LP64)
1821 		status = dump_elf64(dtp, dof, fd);
1822 	else
1823 		status = dump_elf32(dtp, dof, fd);
1824 
1825 	if (status != 0)
1826 		return (dt_link_error(dtp, NULL, -1, NULL,
1827 		    "failed to write %s: %s", tfile,
1828 		    strerror(dtrace_errno(dtp))));
1829 
1830 	if (!dtp->dt_lazyload) {
1831 		const char *fmt = "%s -o %s -r %s %s";
1832 		dt_dirpath_t *dp = dt_list_next(&dtp->dt_lib_path);
1833 
1834 		(void) snprintf(drti, sizeof (drti), "%s/drti.o", dp->dir_path);
1835 
1836 		len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, tfile,
1837 		    drti) + 1;
1838 
1839 		cmd = alloca(len);
1840 
1841 		(void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, tfile,
1842 		    drti);
1843 		if ((status = system(cmd)) == -1) {
1844 			ret = dt_link_error(dtp, NULL, fd, NULL,
1845 			    "failed to run %s: %s", dtp->dt_ld_path,
1846 			    strerror(errno));
1847 			goto done;
1848 		}
1849 
1850 		if (WIFSIGNALED(status)) {
1851 			ret = dt_link_error(dtp, NULL, fd, NULL,
1852 			    "failed to link %s: %s failed due to signal %d",
1853 			    file, dtp->dt_ld_path, WTERMSIG(status));
1854 			goto done;
1855 		}
1856 
1857 		if (WEXITSTATUS(status) != 0) {
1858 			ret = dt_link_error(dtp, NULL, fd, NULL,
1859 			    "failed to link %s: %s exited with status %d\n",
1860 			    file, dtp->dt_ld_path, WEXITSTATUS(status));
1861 			goto done;
1862 		}
1863 		(void) close(fd); /* release temporary file */
1864 
1865 		/*
1866 		 * Now that we've linked drti.o, reduce the global __SUNW_dof
1867 		 * symbol to a local symbol. This is needed to so that multiple
1868 		 * generated object files (for different providers, for
1869 		 * instance) can be linked together. This is accomplished using
1870 		 * the -Blocal flag with Sun's linker, but GNU ld doesn't appear
1871 		 * to have an equivalent option.
1872 		 */
1873 		asprintf(&cmd, "%s --localize-hidden %s", dtp->dt_objcopy_path,
1874 		    file);
1875 		if ((status = system(cmd)) == -1) {
1876 			ret = dt_link_error(dtp, NULL, -1, NULL,
1877 			    "failed to run %s: %s", dtp->dt_objcopy_path,
1878 			    strerror(errno));
1879 			free(cmd);
1880 			goto done;
1881 		}
1882 		free(cmd);
1883 
1884 		if (WIFSIGNALED(status)) {
1885 			ret = dt_link_error(dtp, NULL, -1, NULL,
1886 			    "failed to link %s: %s failed due to signal %d",
1887 			    file, dtp->dt_objcopy_path, WTERMSIG(status));
1888 			goto done;
1889 		}
1890 
1891 		if (WEXITSTATUS(status) != 0) {
1892 			ret = dt_link_error(dtp, NULL, -1, NULL,
1893 			    "failed to link %s: %s exited with status %d\n",
1894 			    file, dtp->dt_objcopy_path, WEXITSTATUS(status));
1895 			goto done;
1896 		}
1897 	} else {
1898 		if (rename(tfile, file) != 0) {
1899 			ret = dt_link_error(dtp, NULL, fd, NULL,
1900 			    "failed to rename %s to %s: %s", tfile, file,
1901 			    strerror(errno));
1902 			goto done;
1903 		}
1904 		(void) close(fd);
1905 	}
1906 
1907 done:
1908 	dtrace_dof_destroy(dtp, dof);
1909 
1910 	if (!dtp->dt_lazyload)
1911 		(void) unlink(tfile);
1912 	return (ret);
1913 }
1914