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