4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright (c) 2015, Joyent, Inc.
30 * Routines for writing ctf data to elf files, originally from the ctf tools.
33 #include <libctf_impl.h>
37 #include <sys/types.h>
44 ctf_write_elf(ctf_file_t
*fp
, Elf
*src
, Elf
*dst
, int flags
)
46 GElf_Ehdr sehdr
, dehdr
;
48 Elf_Data
*sdata
, *ddata
;
53 int compress
= (flags
& CTF_ELFWRITE_F_COMPRESS
);
55 int srcidx
, dstidx
, pad
, i
;
59 size_t nshdr
, nphdr
, strndx
;
60 void *strdatabuf
= NULL
, *symdatabuf
= NULL
;
61 size_t strdatasz
= 0, symdatasz
= 0;
64 size_t elfsize
, asize
;
66 if ((flags
& ~(CTF_ELFWRITE_F_COMPRESS
)) != 0) {
67 ret
= ctf_set_errno(fp
, EINVAL
);
71 if (gelf_newehdr(dst
, gelf_getclass(src
)) == 0) {
72 ret
= ctf_set_errno(fp
, ECTF_ELF
);
75 if (gelf_getehdr(src
, &sehdr
) == NULL
) {
76 ret
= ctf_set_errno(fp
, ECTF_ELF
);
79 (void) memcpy(&dehdr
, &sehdr
, sizeof (GElf_Ehdr
));
80 if (gelf_update_ehdr(dst
, &dehdr
) == 0) {
81 ret
= ctf_set_errno(fp
, ECTF_ELF
);
86 * Use libelf to get the number of sections and the string section to
87 * deal with ELF files that may have a large number of sections. We just
88 * always use this to make our live easier.
90 if (elf_getphdrnum(src
, &nphdr
) != 0) {
91 ret
= ctf_set_errno(fp
, ECTF_ELF
);
94 if (elf_getshdrnum(src
, &nshdr
) != 0) {
95 ret
= ctf_set_errno(fp
, ECTF_ELF
);
98 if (elf_getshdrstrndx(src
, &strndx
) != 0) {
99 ret
= ctf_set_errno(fp
, ECTF_ELF
);
104 * Neither the existing debug sections nor the SUNW_ctf sections (new or
105 * existing) are SHF_ALLOC'd, so they won't be in areas referenced by
106 * program headers. As such, we can just blindly copy the program
107 * headers from the existing file to the new file.
110 (void) elf_flagelf(dst
, ELF_C_SET
, ELF_F_LAYOUT
);
111 if (gelf_newphdr(dst
, nphdr
) == 0) {
112 ret
= ctf_set_errno(fp
, ECTF_ELF
);
116 for (i
= 0; i
< nphdr
; i
++) {
119 if (gelf_getphdr(src
, i
, &phdr
) == NULL
) {
120 ret
= ctf_set_errno(fp
, ECTF_ELF
);
123 if (gelf_update_phdr(dst
, i
, &phdr
) == 0) {
124 ret
= ctf_set_errno(fp
, ECTF_ELF
);
130 secxlate
= ctf_alloc(sizeof (int) * nshdr
);
131 for (srcidx
= dstidx
= 0; srcidx
< nshdr
; srcidx
++) {
132 Elf_Scn
*scn
= elf_getscn(src
, srcidx
);
136 if (gelf_getshdr(scn
, &shdr
) == NULL
) {
137 ret
= ctf_set_errno(fp
, ECTF_ELF
);
140 sname
= elf_strptr(src
, strndx
, shdr
.sh_name
);
142 ret
= ctf_set_errno(fp
, ECTF_ELF
);
146 if (strcmp(sname
, CTF_ELF_SCN_NAME
) == 0) {
147 secxlate
[srcidx
] = -1;
149 secxlate
[srcidx
] = dstidx
++;
150 curnmoff
+= strlen(sname
) + 1;
153 new_offset
= (off_t
)dehdr
.e_phoff
;
156 for (srcidx
= 1; srcidx
< nshdr
; srcidx
++) {
159 sscn
= elf_getscn(src
, srcidx
);
160 if (gelf_getshdr(sscn
, &shdr
) == NULL
) {
161 ret
= ctf_set_errno(fp
, ECTF_ELF
);
165 if (secxlate
[srcidx
] == -1) {
170 dscn
= elf_newscn(dst
);
172 ret
= ctf_set_errno(fp
, ECTF_ELF
);
177 * If this file has program headers, we need to explicitly lay
178 * out sections. If none of the sections prior to this one have
179 * been removed, then we can just use the existing location. If
180 * one or more sections have been changed, then we need to
181 * adjust this one to avoid holes.
183 if (changing
&& nphdr
!= 0) {
184 pad
= new_offset
% shdr
.sh_addralign
;
187 new_offset
+= shdr
.sh_addralign
- pad
;
188 shdr
.sh_offset
= new_offset
;
191 shdr
.sh_link
= secxlate
[shdr
.sh_link
];
193 if (shdr
.sh_type
== SHT_REL
|| shdr
.sh_type
== SHT_RELA
)
194 shdr
.sh_info
= secxlate
[shdr
.sh_info
];
196 sname
= elf_strptr(src
, strndx
, shdr
.sh_name
);
198 ret
= ctf_set_errno(fp
, ECTF_ELF
);
201 if ((sdata
= elf_getdata(sscn
, NULL
)) == NULL
) {
202 ret
= ctf_set_errno(fp
, ECTF_ELF
);
205 if ((ddata
= elf_newdata(dscn
)) == NULL
) {
206 ret
= ctf_set_errno(fp
, ECTF_ELF
);
209 bcopy(sdata
, ddata
, sizeof (Elf_Data
));
211 if (srcidx
== strndx
) {
212 char seclen
= strlen(CTF_ELF_SCN_NAME
);
214 strdatasz
= ddata
->d_size
+ shdr
.sh_size
+
216 ddata
->d_buf
= strdatabuf
= ctf_alloc(strdatasz
);
217 if (ddata
->d_buf
== NULL
) {
218 ret
= ctf_set_errno(fp
, ECTF_ELF
);
221 bcopy(sdata
->d_buf
, ddata
->d_buf
, shdr
.sh_size
);
222 (void) strcpy((caddr_t
)ddata
->d_buf
+ shdr
.sh_size
,
224 ctfnameoff
= (off_t
)shdr
.sh_size
;
225 shdr
.sh_size
+= seclen
+ 1;
226 ddata
->d_size
+= seclen
+ 1;
232 if (shdr
.sh_type
== SHT_SYMTAB
&& shdr
.sh_entsize
!= 0) {
233 int nsym
= shdr
.sh_size
/ shdr
.sh_entsize
;
235 symtab_idx
= secxlate
[srcidx
];
237 symdatasz
= shdr
.sh_size
;
238 ddata
->d_buf
= symdatabuf
= ctf_alloc(symdatasz
);
239 if (ddata
->d_buf
== NULL
) {
240 ret
= ctf_set_errno(fp
, ECTF_ELF
);
243 (void) bcopy(sdata
->d_buf
, ddata
->d_buf
, shdr
.sh_size
);
245 for (i
= 0; i
< nsym
; i
++) {
249 (void) gelf_getsym(ddata
, i
, &sym
);
251 if (sym
.st_shndx
>= SHN_LORESERVE
)
254 if ((newscn
= secxlate
[sym
.st_shndx
]) !=
257 (newscn
== -1 ? 1 : newscn
);
259 if (gelf_update_sym(ddata
, i
, &sym
) ==
261 ret
= ctf_set_errno(fp
,
269 if (gelf_update_shdr(dscn
, &shdr
) == 0) {
270 ret
= ctf_set_errno(fp
, ECTF_ELF
);
274 new_offset
= (off_t
)shdr
.sh_offset
;
275 if (shdr
.sh_type
!= SHT_NOBITS
)
276 new_offset
+= shdr
.sh_size
;
279 if (symtab_idx
== -1) {
280 ret
= ctf_set_errno(fp
, ECTF_ELF
);
284 /* Add the ctf section */
285 if ((dscn
= elf_newscn(dst
)) == NULL
) {
286 ret
= ctf_set_errno(fp
, ECTF_ELF
);
289 if (gelf_getshdr(dscn
, &shdr
) == NULL
) {
290 ret
= ctf_set_errno(fp
, ECTF_ELF
);
293 shdr
.sh_name
= ctfnameoff
;
294 shdr
.sh_type
= SHT_PROGBITS
;
295 shdr
.sh_size
= fp
->ctf_size
;
296 shdr
.sh_link
= symtab_idx
;
297 shdr
.sh_addralign
= 4;
298 if (changing
&& nphdr
!= 0) {
299 pad
= new_offset
% shdr
.sh_addralign
;
302 new_offset
+= shdr
.sh_addralign
- pad
;
304 shdr
.sh_offset
= new_offset
;
305 new_offset
+= shdr
.sh_size
;
308 if ((ddata
= elf_newdata(dscn
)) == NULL
) {
309 ret
= ctf_set_errno(fp
, ECTF_ELF
);
316 if (ctf_zopen(&err
) == NULL
) {
317 ret
= ctf_set_errno(fp
, err
);
321 if ((err
= ctf_compress(fp
, &cdata
, &asize
, &elfsize
)) != 0) {
322 ret
= ctf_set_errno(fp
, err
);
325 ddata
->d_buf
= cdata
;
326 ddata
->d_size
= elfsize
;
328 ddata
->d_buf
= (void *)fp
->ctf_base
;
329 ddata
->d_size
= fp
->ctf_size
;
331 ddata
->d_align
= shdr
.sh_addralign
;
333 if (gelf_update_shdr(dscn
, &shdr
) == 0) {
334 ret
= ctf_set_errno(fp
, ECTF_ELF
);
338 /* update the section header location */
340 size_t align
= gelf_fsize(dst
, ELF_T_ADDR
, 1, EV_CURRENT
);
341 size_t r
= new_offset
% align
;
344 new_offset
+= align
- r
;
346 dehdr
.e_shoff
= new_offset
;
350 if (sehdr
.e_shstrndx
== SHN_XINDEX
)
351 dehdr
.e_shstrndx
= SHN_XINDEX
;
353 dehdr
.e_shstrndx
= secxlate
[sehdr
.e_shstrndx
];
354 if (gelf_update_ehdr(dst
, &dehdr
) == 0) {
355 ret
= ctf_set_errno(fp
, ECTF_ELF
);
358 if (elf_update(dst
, ELF_C_WRITE
) < 0) {
359 ret
= ctf_set_errno(fp
, ECTF_ELF
);
366 if (strdatabuf
!= NULL
)
367 ctf_free(strdatabuf
, strdatasz
);
368 if (symdatabuf
!= NULL
)
369 ctf_free(symdatabuf
, symdatasz
);
371 ctf_data_free(cdata
, fp
->ctf_size
);
372 if (secxlate
!= NULL
)
373 ctf_free(secxlate
, sizeof (int) * nshdr
);
379 ctf_elffdwrite(ctf_file_t
*fp
, int ifd
, int ofd
, int flags
)
384 (void) elf_version(EV_CURRENT
);
385 if ((ielf
= elf_begin(ifd
, ELF_C_READ
, NULL
)) == NULL
)
386 return (ctf_set_errno(fp
, ECTF_ELF
));
388 if ((oelf
= elf_begin(ofd
, ELF_C_WRITE
, NULL
)) == NULL
)
389 return (ctf_set_errno(fp
, ECTF_ELF
));
391 ret
= ctf_write_elf(fp
, ielf
, oelf
, flags
);
393 (void) elf_end(ielf
);
394 (void) elf_end(oelf
);
400 ctf_elfwrite(ctf_file_t
*fp
, const char *input
, const char *output
, int flags
)
405 if ((ifd
= open(input
, O_RDONLY
)) < 0)
406 return (ctf_set_errno(fp
, errno
));
408 if (fstat(ifd
, &st
) < 0)
409 return (ctf_set_errno(fp
, errno
));
411 if ((ofd
= open(output
, O_RDWR
| O_CREAT
| O_TRUNC
, st
.st_mode
)) < 0)
412 return (ctf_set_errno(fp
, errno
));
414 ret
= ctf_elffdwrite(fp
, ifd
, ofd
, flags
);
416 if (close(ifd
) != 0 && ret
!= 0)
417 ret
= ctf_set_errno(fp
, errno
);
418 if (close(ofd
) != 0 && ret
!= 0)
419 ret
= ctf_set_errno(fp
, errno
);