/src/binutils-gdb/libctf/ctf-open-bfd.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Opening CTF files with BFD. |
2 | | Copyright (C) 2019-2025 Free Software Foundation, Inc. |
3 | | |
4 | | This file is part of libctf. |
5 | | |
6 | | libctf is free software; you can redistribute it and/or modify it under |
7 | | the terms of the GNU General Public License as published by the Free |
8 | | Software Foundation; either version 3, or (at your option) any later |
9 | | version. |
10 | | |
11 | | This program is distributed in the hope that it will be useful, but |
12 | | WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
14 | | See the GNU General Public License for more details. |
15 | | |
16 | | You should have received a copy of the GNU General Public License |
17 | | along with this program; see the file COPYING. If not see |
18 | | <http://www.gnu.org/licenses/>. */ |
19 | | |
20 | | #include <ctf-impl.h> |
21 | | #include <stddef.h> |
22 | | #include <assert.h> |
23 | | #include <sys/types.h> |
24 | | #include <sys/stat.h> |
25 | | #include <errno.h> |
26 | | #include <string.h> |
27 | | #include <fcntl.h> |
28 | | #include <unistd.h> |
29 | | #include <elf.h> |
30 | | #include <bfd.h> |
31 | | #include "swap.h" |
32 | | #include "ctf-endian.h" |
33 | | |
34 | | #include "elf-bfd.h" |
35 | | |
36 | | /* Free the BFD bits of a CTF file on ctf_arc_close(). */ |
37 | | |
38 | | static void |
39 | | ctf_bfdclose (struct ctf_archive_internal *arci) |
40 | 0 | { |
41 | 0 | if (arci->ctfi_abfd != NULL) |
42 | 0 | if (!bfd_close_all_done (arci->ctfi_abfd)) |
43 | 0 | ctf_err_warn (NULL, 0, 0, _("cannot close BFD: %s"), |
44 | 0 | bfd_errmsg (bfd_get_error ())); |
45 | 0 | } |
46 | | |
47 | | /* Open a CTF file given the specified BFD. */ |
48 | | |
49 | | ctf_archive_t * |
50 | | ctf_bfdopen (struct bfd *abfd, int *errp) |
51 | 0 | { |
52 | 0 | ctf_archive_t *arc; |
53 | 0 | asection *ctf_asect; |
54 | 0 | bfd_byte *contents; |
55 | 0 | ctf_sect_t ctfsect; |
56 | |
|
57 | 0 | libctf_init_debug(); |
58 | |
|
59 | 0 | if ((ctf_asect = bfd_get_section_by_name (abfd, _CTF_SECTION)) == NULL) |
60 | 0 | { |
61 | 0 | return (ctf_set_open_errno (errp, ECTF_NOCTFDATA)); |
62 | 0 | } |
63 | | |
64 | 0 | if (!bfd_malloc_and_get_section (abfd, ctf_asect, &contents)) |
65 | 0 | { |
66 | 0 | ctf_err_warn (NULL, 0, 0, _("ctf_bfdopen(): cannot malloc " |
67 | 0 | "CTF section: %s"), |
68 | 0 | bfd_errmsg (bfd_get_error ())); |
69 | 0 | return (ctf_set_open_errno (errp, ECTF_FMT)); |
70 | 0 | } |
71 | | |
72 | 0 | ctfsect.cts_name = _CTF_SECTION; |
73 | 0 | ctfsect.cts_entsize = 1; |
74 | 0 | ctfsect.cts_size = bfd_section_size (ctf_asect); |
75 | 0 | ctfsect.cts_data = contents; |
76 | |
|
77 | 0 | if ((arc = ctf_bfdopen_ctfsect (abfd, &ctfsect, errp)) != NULL) |
78 | 0 | { |
79 | | /* This frees the cts_data later. */ |
80 | 0 | arc->ctfi_data = (void *) ctfsect.cts_data; |
81 | 0 | return arc; |
82 | 0 | } |
83 | | |
84 | 0 | free (contents); |
85 | 0 | return NULL; /* errno is set for us. */ |
86 | 0 | } |
87 | | |
88 | | /* Open a CTF file given the specified BFD and CTF section (which may contain a |
89 | | CTF archive or a file). */ |
90 | | |
91 | | ctf_archive_t * |
92 | | ctf_bfdopen_ctfsect (struct bfd *abfd _libctf_unused_, |
93 | | const ctf_sect_t *ctfsect, int *errp) |
94 | 0 | { |
95 | 0 | ctf_archive_t *arci; |
96 | 0 | ctf_sect_t *symsectp = NULL; |
97 | 0 | ctf_sect_t *strsectp = NULL; |
98 | 0 | const char *bfderrstr = NULL; |
99 | 0 | char *strtab_alloc = NULL; |
100 | 0 | int symsect_endianness = -1; |
101 | |
|
102 | 0 | libctf_init_debug(); |
103 | |
|
104 | 0 | #ifdef HAVE_BFD_ELF |
105 | 0 | ctf_sect_t symsect, strsect; |
106 | 0 | Elf_Internal_Shdr *symhdr; |
107 | 0 | size_t symcount; |
108 | 0 | Elf_Internal_Sym *isymbuf; |
109 | 0 | bfd_byte *symtab = NULL; |
110 | 0 | const char *symtab_name; |
111 | 0 | const char *strtab = NULL; |
112 | 0 | const char *strtab_name; |
113 | 0 | size_t strsize; |
114 | 0 | const ctf_preamble_t *preamble; |
115 | |
|
116 | 0 | if (ctfsect->cts_data == NULL) |
117 | 0 | { |
118 | 0 | bfderrstr = N_("CTF section is NULL"); |
119 | 0 | goto err; |
120 | 0 | } |
121 | 0 | preamble = ctf_arc_bufpreamble (ctfsect); |
122 | |
|
123 | 0 | if (preamble->ctp_flags & CTF_F_DYNSTR) |
124 | 0 | { |
125 | 0 | symhdr = &elf_tdata (abfd)->dynsymtab_hdr; |
126 | 0 | strtab_name = ".dynstr"; |
127 | 0 | symtab_name = ".dynsym"; |
128 | 0 | } |
129 | 0 | else |
130 | 0 | { |
131 | 0 | symhdr = &elf_tdata (abfd)->symtab_hdr; |
132 | 0 | strtab_name = ".strtab"; |
133 | 0 | symtab_name = ".symtab"; |
134 | 0 | } |
135 | | |
136 | | /* TODO: handle SYMTAB_SHNDX. */ |
137 | | |
138 | | /* Get the symtab, and the strtab associated with it. */ |
139 | 0 | if (elf_tdata (abfd) && symhdr && symhdr->sh_size && symhdr->sh_entsize) |
140 | 0 | { |
141 | 0 | symcount = symhdr->sh_size / symhdr->sh_entsize; |
142 | 0 | if ((symtab = malloc (symhdr->sh_size)) == NULL) |
143 | 0 | { |
144 | 0 | bfderrstr = N_("cannot malloc symbol table"); |
145 | 0 | goto err; |
146 | 0 | } |
147 | | |
148 | 0 | isymbuf = bfd_elf_get_elf_syms (abfd, symhdr, symcount, 0, |
149 | 0 | NULL, symtab, NULL); |
150 | 0 | free (isymbuf); |
151 | 0 | if (isymbuf == NULL) |
152 | 0 | { |
153 | 0 | bfderrstr = N_("cannot read symbol table"); |
154 | 0 | goto err_free_sym; |
155 | 0 | } |
156 | | |
157 | 0 | if (elf_elfsections (abfd) != NULL |
158 | 0 | && symhdr->sh_link < elf_numsections (abfd)) |
159 | 0 | { |
160 | 0 | Elf_Internal_Shdr *strhdr = elf_elfsections (abfd)[symhdr->sh_link]; |
161 | |
|
162 | 0 | strsize = strhdr->sh_size; |
163 | 0 | if (strhdr->contents == NULL) |
164 | 0 | { |
165 | 0 | if ((strtab = bfd_elf_get_str_section (abfd, symhdr->sh_link)) == NULL) |
166 | 0 | { |
167 | 0 | bfderrstr = N_("cannot read string table"); |
168 | 0 | goto err_free_sym; |
169 | 0 | } |
170 | 0 | } |
171 | 0 | else |
172 | 0 | strtab = (const char *) strhdr->contents; |
173 | 0 | } |
174 | 0 | } |
175 | 0 | else /* No symtab: just try getting .strtab or .dynstr by name. */ |
176 | 0 | { |
177 | 0 | bfd_byte *str_bcontents; |
178 | 0 | asection *str_asect; |
179 | |
|
180 | 0 | if ((str_asect = bfd_get_section_by_name (abfd, strtab_name)) != NULL) |
181 | 0 | { |
182 | 0 | if (bfd_malloc_and_get_section (abfd, str_asect, &str_bcontents)) |
183 | 0 | { |
184 | 0 | strtab = (const char *) str_bcontents; |
185 | 0 | strtab_alloc = (char *) str_bcontents; |
186 | 0 | strsize = str_asect->size; |
187 | 0 | } |
188 | 0 | } |
189 | 0 | } |
190 | | |
191 | 0 | if (strtab) |
192 | 0 | { |
193 | | /* The names here are more or less arbitrary, but there is no point |
194 | | thrashing around digging the name out of the shstrtab given that we don't |
195 | | use it for anything but debugging. */ |
196 | |
|
197 | 0 | strsect.cts_data = strtab; |
198 | 0 | strsect.cts_name = strtab_name; |
199 | 0 | strsect.cts_size = strsize; |
200 | 0 | strsectp = &strsect; |
201 | 0 | } |
202 | |
|
203 | 0 | if (symtab) |
204 | 0 | { |
205 | 0 | assert (symhdr->sh_entsize == get_elf_backend_data (abfd)->s->sizeof_sym); |
206 | 0 | symsect.cts_name = symtab_name; |
207 | 0 | symsect.cts_entsize = symhdr->sh_entsize; |
208 | 0 | symsect.cts_size = symhdr->sh_size; |
209 | 0 | symsect.cts_data = symtab; |
210 | 0 | symsectp = &symsect; |
211 | 0 | } |
212 | | |
213 | 0 | symsect_endianness = bfd_little_endian (abfd); |
214 | 0 | #endif |
215 | |
|
216 | 0 | arci = ctf_arc_bufopen (ctfsect, symsectp, strsectp, errp); |
217 | 0 | if (arci) |
218 | 0 | { |
219 | | /* Request freeing of the symsect and possibly the strsect. */ |
220 | 0 | arci->ctfi_free_symsect = 1; |
221 | 0 | if (strtab_alloc) |
222 | 0 | arci->ctfi_free_strsect = 1; |
223 | | |
224 | | /* Get the endianness right. */ |
225 | 0 | if (symsect_endianness > -1) |
226 | 0 | ctf_arc_symsect_endianness (arci, symsect_endianness); |
227 | 0 | return arci; |
228 | 0 | } |
229 | 0 | #ifdef HAVE_BFD_ELF |
230 | 0 | err_free_sym: |
231 | 0 | free (symtab); |
232 | 0 | free (strtab_alloc); |
233 | 0 | #endif |
234 | 0 | err: _libctf_unused_; |
235 | 0 | if (bfderrstr) |
236 | 0 | { |
237 | 0 | ctf_err_warn (NULL, 0, 0, "ctf_bfdopen(): %s: %s", gettext (bfderrstr), |
238 | 0 | bfd_errmsg (bfd_get_error())); |
239 | 0 | ctf_set_open_errno (errp, ECTF_FMT); |
240 | 0 | } |
241 | 0 | return NULL; |
242 | 0 | } |
243 | | |
244 | | /* Open the specified file descriptor and return a pointer to a CTF archive that |
245 | | contains one or more CTF dicts. The file can be an ELF file, a file |
246 | | containing raw CTF, or a CTF archive. The caller is responsible for closing |
247 | | the file descriptor when it is no longer needed. If this is an ELF file, |
248 | | TARGET, if non-NULL, should be the name of a suitable BFD target. */ |
249 | | |
250 | | ctf_archive_t * |
251 | | ctf_fdopen (int fd, const char *filename, const char *target, int *errp) |
252 | 0 | { |
253 | 0 | ctf_archive_t *arci; |
254 | 0 | bfd *abfd; |
255 | 0 | int nfd; |
256 | |
|
257 | 0 | struct stat st; |
258 | 0 | ssize_t nbytes; |
259 | |
|
260 | 0 | ctf_preamble_t ctfhdr; |
261 | 0 | uint64_t arc_magic; |
262 | |
|
263 | 0 | memset (&ctfhdr, 0, sizeof (ctfhdr)); |
264 | |
|
265 | 0 | libctf_init_debug(); |
266 | |
|
267 | 0 | if (fstat (fd, &st) == -1) |
268 | 0 | return (ctf_set_open_errno (errp, errno)); |
269 | | |
270 | 0 | if ((nbytes = ctf_pread (fd, &ctfhdr, sizeof (ctfhdr), 0)) <= 0) |
271 | 0 | return (ctf_set_open_errno (errp, nbytes < 0 ? errno : ECTF_FMT)); |
272 | | |
273 | | /* If we have read enough bytes to form a CTF header and the magic string |
274 | | matches, in either endianness, attempt to interpret the file as raw |
275 | | CTF. */ |
276 | | |
277 | 0 | if ((size_t) nbytes >= sizeof (ctf_preamble_t) |
278 | 0 | && (ctfhdr.ctp_magic == CTF_MAGIC |
279 | 0 | || ctfhdr.ctp_magic == bswap_16 (CTF_MAGIC))) |
280 | 0 | { |
281 | 0 | ctf_dict_t *fp = NULL; |
282 | 0 | void *data; |
283 | |
|
284 | 0 | if ((data = ctf_mmap (st.st_size, 0, fd)) == NULL) |
285 | 0 | return (ctf_set_open_errno (errp, errno)); |
286 | | |
287 | 0 | if ((fp = ctf_simple_open (data, (size_t) st.st_size, NULL, 0, 0, |
288 | 0 | NULL, 0, errp)) == NULL) |
289 | 0 | { |
290 | 0 | ctf_munmap (data, (size_t) st.st_size); |
291 | 0 | return NULL; /* errno is set for us. */ |
292 | 0 | } |
293 | | |
294 | 0 | fp->ctf_data_mmapped = data; |
295 | 0 | fp->ctf_data_mmapped_len = (size_t) st.st_size; |
296 | |
|
297 | 0 | return ctf_new_archive_internal (0, 1, NULL, fp, NULL, NULL, errp); |
298 | 0 | } |
299 | | |
300 | 0 | if ((nbytes = ctf_pread (fd, &arc_magic, sizeof (arc_magic), 0)) <= 0) |
301 | 0 | return (ctf_set_open_errno (errp, nbytes < 0 ? errno : ECTF_FMT)); |
302 | | |
303 | 0 | if ((size_t) nbytes >= sizeof (uint64_t) && le64toh (arc_magic) == CTFA_MAGIC) |
304 | 0 | { |
305 | 0 | struct ctf_archive *arc; |
306 | |
|
307 | 0 | if ((arc = ctf_arc_open_internal (filename, errp)) == NULL) |
308 | 0 | return NULL; /* errno is set for us. */ |
309 | | |
310 | 0 | return ctf_new_archive_internal (1, 1, arc, NULL, NULL, NULL, errp); |
311 | 0 | } |
312 | | |
313 | | /* Attempt to open the file with BFD. We must dup the fd first, since bfd |
314 | | takes ownership of the passed fd. */ |
315 | | |
316 | 0 | if ((nfd = dup (fd)) < 0) |
317 | 0 | return (ctf_set_open_errno (errp, errno)); |
318 | | |
319 | 0 | if ((abfd = bfd_fdopenr (filename, target, nfd)) == NULL) |
320 | 0 | { |
321 | 0 | ctf_err_warn (NULL, 0, 0, _("cannot open BFD from %s: %s"), |
322 | 0 | filename ? filename : _("(unknown file)"), |
323 | 0 | bfd_errmsg (bfd_get_error ())); |
324 | 0 | return (ctf_set_open_errno (errp, ECTF_FMT)); |
325 | 0 | } |
326 | 0 | bfd_set_cacheable (abfd, 1); |
327 | |
|
328 | 0 | if (!bfd_check_format (abfd, bfd_object)) |
329 | 0 | { |
330 | 0 | ctf_err_warn (NULL, 0, 0, _("BFD format problem in %s: %s"), |
331 | 0 | filename ? filename : _("(unknown file)"), |
332 | 0 | bfd_errmsg (bfd_get_error ())); |
333 | 0 | if (bfd_get_error() == bfd_error_file_ambiguously_recognized) |
334 | 0 | return (ctf_set_open_errno (errp, ECTF_BFD_AMBIGUOUS)); |
335 | 0 | else |
336 | 0 | return (ctf_set_open_errno (errp, ECTF_FMT)); |
337 | 0 | } |
338 | | |
339 | 0 | if ((arci = ctf_bfdopen (abfd, errp)) == NULL) |
340 | 0 | { |
341 | 0 | if (!bfd_close_all_done (abfd)) |
342 | 0 | ctf_err_warn (NULL, 0, 0, _("cannot close BFD: %s"), |
343 | 0 | bfd_errmsg (bfd_get_error ())); |
344 | 0 | return NULL; /* errno is set for us. */ |
345 | 0 | } |
346 | 0 | arci->ctfi_bfd_close = ctf_bfdclose; |
347 | 0 | arci->ctfi_abfd = abfd; |
348 | |
|
349 | 0 | return arci; |
350 | 0 | } |
351 | | |
352 | | /* Open the specified file and return a pointer to a CTF dict. The file |
353 | | can be either an ELF file or raw CTF file. This is just a convenient |
354 | | wrapper around ctf_fdopen() for callers. */ |
355 | | |
356 | | ctf_archive_t * |
357 | | ctf_open (const char *filename, const char *target, int *errp) |
358 | 0 | { |
359 | 0 | ctf_archive_t *arc; |
360 | 0 | int fd; |
361 | |
|
362 | 0 | if ((fd = open (filename, O_RDONLY)) == -1) |
363 | 0 | { |
364 | 0 | if (errp != NULL) |
365 | 0 | *errp = errno; |
366 | 0 | return NULL; |
367 | 0 | } |
368 | | |
369 | 0 | arc = ctf_fdopen (fd, filename, target, errp); |
370 | 0 | (void) close (fd); |
371 | 0 | return arc; |
372 | 0 | } |
373 | | |
374 | | /* Public entry point: open a CTF archive, or CTF file. Returns the archive, or |
375 | | NULL and an error in *err. Despite the fact that this uses CTF archives, it |
376 | | must be in this file to avoid dragging in BFD into non-BFD-using programs. */ |
377 | | ctf_archive_t * |
378 | | ctf_arc_open (const char *filename, int *errp) |
379 | 0 | { |
380 | 0 | return ctf_open (filename, NULL, errp); |
381 | 0 | } |