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