2 Copyright (C) 2019-2020 Free Software Foundation, Inc.
4 This file is part of libctf.
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
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.
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/>. */
21 #include <sys/types.h>
24 #include "ctf-endian.h"
35 static off_t
arc_write_one_ctf (ctf_file_t
* f
, int fd
, size_t threshold
);
36 static ctf_file_t
*ctf_arc_open_by_offset (const struct ctf_archive
*arc
,
37 const ctf_sect_t
*symsect
,
38 const ctf_sect_t
*strsect
,
39 size_t offset
, int *errp
);
40 static int sort_modent_by_name (const void *one
, const void *two
, void *n
);
41 static void *arc_mmap_header (int fd
, size_t headersz
);
42 static void *arc_mmap_file (int fd
, size_t size
);
43 static int arc_mmap_writeout (int fd
, void *header
, size_t headersz
,
45 static int arc_mmap_unmap (void *header
, size_t headersz
, const char **errmsg
);
47 /* Write out a CTF archive to the start of the file referenced by the passed-in
48 fd. The entries in CTF_FILES are referenced by name: the names are passed in
49 the names array, which must have CTF_FILES entries.
51 Returns 0 on success, or an errno, or an ECTF_* value. */
53 ctf_arc_write_fd (int fd
, ctf_file_t
**ctf_files
, size_t ctf_file_cnt
,
54 const char **names
, size_t threshold
)
57 struct ctf_archive
*archdr
;
62 size_t ctf_startoffs
; /* Start of the section we are working over. */
63 char *nametbl
= NULL
; /* The name table. */
66 struct ctf_archive_modent
*modent
;
68 ctf_dprintf ("Writing CTF archive with %lu files\n",
69 (unsigned long) ctf_file_cnt
);
71 /* Figure out the size of the mmap()ed header, including the
72 ctf_archive_modent array. We assume that all of this needs no
73 padding: a likely assumption, given that it's all made up of
75 headersz
= sizeof (struct ctf_archive
)
76 + (ctf_file_cnt
* sizeof (uint64_t) * 2);
77 ctf_dprintf ("headersz is %lu\n", (unsigned long) headersz
);
79 /* From now on we work in two pieces: an mmap()ed region from zero up to the
80 headersz, and a region updated via write() starting after that, containing
81 all the tables. Platforms that do not support mmap() just use write(). */
82 ctf_startoffs
= headersz
;
83 if (lseek (fd
, ctf_startoffs
- 1, SEEK_SET
) < 0)
85 errmsg
= "ctf_arc_write(): cannot extend file while writing: %s\n";
89 if (write (fd
, &dummy
, 1) < 0)
91 errmsg
= "ctf_arc_write(): cannot extend file while writing: %s\n";
95 if ((archdr
= arc_mmap_header (fd
, headersz
)) == NULL
)
97 errmsg
= "ctf_arc_write(): Cannot mmap(): %s\n";
101 /* Fill in everything we can, which is everything other than the name
103 archdr
->ctfa_magic
= htole64 (CTFA_MAGIC
);
104 archdr
->ctfa_nfiles
= htole64 (ctf_file_cnt
);
105 archdr
->ctfa_ctfs
= htole64 (ctf_startoffs
);
107 /* We could validate that all CTF files have the same data model, but
108 since any reasonable construction process will be building things of
109 only one bitness anyway, this is pretty pointless, so just use the
110 model of the first CTF file for all of them. (It *is* valid to
111 create an empty archive: the value of ctfa_model is irrelevant in
112 this case, but we must be sure not to dereference uninitialized
115 if (ctf_file_cnt
> 0)
116 archdr
->ctfa_model
= htole64 (ctf_getmodel (ctf_files
[0]));
118 /* Now write out the CTFs: ctf_archive_modent array via the mapping,
119 ctfs via write(). The names themselves have not been written yet: we
120 track them in a local strtab until the time is right, and sort the
121 modents array after construction.
123 The name table is not sorted. */
125 for (i
= 0, namesz
= 0; i
< le64toh (archdr
->ctfa_nfiles
); i
++)
126 namesz
+= strlen (names
[i
]) + 1;
128 nametbl
= malloc (namesz
);
131 errmsg
= "Error writing named CTF to archive: %s\n";
135 for (i
= 0, namesz
= 0,
136 modent
= (ctf_archive_modent_t
*) ((char *) archdr
137 + sizeof (struct ctf_archive
));
138 i
< le64toh (archdr
->ctfa_nfiles
); i
++)
142 strcpy (&nametbl
[namesz
], names
[i
]);
144 off
= arc_write_one_ctf (ctf_files
[i
], fd
, threshold
);
145 if ((off
< 0) && (off
> -ECTF_BASE
))
147 errmsg
= "ctf_arc_write(): Cannot determine file "
148 "position while writing to archive: %s";
153 errmsg
= "ctf_arc_write(): Cannot write CTF file to archive: %s\n";
158 modent
->name_offset
= htole64 (namesz
);
159 modent
->ctf_offset
= htole64 (off
- ctf_startoffs
);
160 namesz
+= strlen (names
[i
]) + 1;
164 ctf_qsort_r ((ctf_archive_modent_t
*) ((char *) archdr
165 + sizeof (struct ctf_archive
)),
166 le64toh (archdr
->ctfa_nfiles
),
167 sizeof (struct ctf_archive_modent
), sort_modent_by_name
,
170 /* Now the name table. */
172 if ((nameoffs
= lseek (fd
, 0, SEEK_CUR
)) < 0)
174 errmsg
= "ctf_arc_write(): Cannot get current file position "
178 archdr
->ctfa_names
= htole64 (nameoffs
);
183 if ((len
= write (fd
, np
, namesz
)) < 0)
185 errmsg
= "ctf_arc_write(): Cannot write name table to archive: %s\n";
193 if (arc_mmap_writeout (fd
, archdr
, headersz
, &errmsg
) < 0)
195 if (arc_mmap_unmap (archdr
, headersz
, &errmsg
) < 0)
202 arc_mmap_unmap (archdr
, headersz
, NULL
);
204 ctf_dprintf (errmsg
, errno
< ECTF_BASE
? strerror (errno
) :
209 /* Write out a CTF archive. The entries in CTF_FILES are referenced by name:
210 the names are passed in the names array, which must have CTF_FILES entries.
212 If the filename is NULL, create a temporary file and return a pointer to it.
214 Returns 0 on success, or an errno, or an ECTF_* value. */
216 ctf_arc_write (const char *file
, ctf_file_t
** ctf_files
, size_t ctf_file_cnt
,
217 const char **names
, size_t threshold
)
222 if ((fd
= open (file
, O_RDWR
| O_CREAT
| O_TRUNC
| O_CLOEXEC
, 0666)) < 0)
224 ctf_dprintf ("ctf_arc_write(): cannot create %s: %s\n", file
,
229 err
= ctf_arc_write_fd (fd
, ctf_files
, ctf_file_cnt
, names
, threshold
);
233 if ((err
= close (fd
)) < 0)
235 ctf_dprintf ("ctf_arc_write(): Cannot close after writing to archive: "
236 "%s\n", strerror (errno
));
254 /* Write one CTF file out. Return the file position of the written file (or
255 rather, of the file-size uint64_t that precedes it): negative return is a
256 negative errno or ctf_errno value. On error, the file position may no longer
257 be at the end of the file. */
259 arc_write_one_ctf (ctf_file_t
* f
, int fd
, size_t threshold
)
265 int (*writefn
) (ctf_file_t
* fp
, int fd
);
267 if (ctf_serialize (f
) < 0)
268 return f
->ctf_errno
* -1;
270 if ((off
= lseek (fd
, 0, SEEK_CUR
)) < 0)
273 if (f
->ctf_size
> threshold
)
274 writefn
= ctf_compress_write
;
278 /* This zero-write turns into the size in a moment. */
279 ctfsz_len
= sizeof (ctfsz
);
280 ctfszp
= (char *) &ctfsz
;
281 while (ctfsz_len
> 0)
283 ssize_t writelen
= write (fd
, ctfszp
, ctfsz_len
);
286 ctfsz_len
-= writelen
;
290 if (writefn (f
, fd
) != 0)
291 return f
->ctf_errno
* -1;
293 if ((end_off
= lseek (fd
, 0, SEEK_CUR
)) < 0)
295 ctfsz
= htole64 (end_off
- off
);
297 if ((lseek (fd
, off
, SEEK_SET
)) < 0)
301 ctfsz_len
= sizeof (ctfsz
);
302 ctfszp
= (char *) &ctfsz
;
303 while (ctfsz_len
> 0)
305 ssize_t writelen
= write (fd
, ctfszp
, ctfsz_len
);
308 ctfsz_len
-= writelen
;
312 end_off
= LCTF_ALIGN_OFFS (end_off
, 8);
313 if ((lseek (fd
, end_off
, SEEK_SET
)) < 0)
319 /* qsort() function to sort the array of struct ctf_archive_modents into
320 ascending name order. */
322 sort_modent_by_name (const void *one
, const void *two
, void *n
)
324 const struct ctf_archive_modent
*a
= one
;
325 const struct ctf_archive_modent
*b
= two
;
328 return strcmp (&nametbl
[le64toh (a
->name_offset
)],
329 &nametbl
[le64toh (b
->name_offset
)]);
332 /* bsearch_r() function to search for a given name in the sorted array of struct
333 ctf_archive_modents. */
335 search_modent_by_name (const void *key
, const void *ent
, void *arg
)
338 const struct ctf_archive_modent
*v
= ent
;
339 const char *search_nametbl
= arg
;
341 return strcmp (k
, &search_nametbl
[le64toh (v
->name_offset
)]);
344 /* Make a new struct ctf_archive_internal wrapper for a ctf_archive or a
345 ctf_file. Closes ARC and/or FP on error. Arrange to free the SYMSECT or
346 STRSECT, as needed, on close. */
348 struct ctf_archive_internal
*
349 ctf_new_archive_internal (int is_archive
, struct ctf_archive
*arc
,
350 ctf_file_t
*fp
, const ctf_sect_t
*symsect
,
351 const ctf_sect_t
*strsect
,
354 struct ctf_archive_internal
*arci
;
356 if ((arci
= calloc (1, sizeof (struct ctf_archive_internal
))) == NULL
)
359 ctf_arc_close_internal (arc
);
362 return (ctf_set_open_errno (errp
, errno
));
364 arci
->ctfi_is_archive
= is_archive
;
366 arci
->ctfi_archive
= arc
;
368 arci
->ctfi_file
= fp
;
370 memcpy (&arci
->ctfi_symsect
, symsect
, sizeof (struct ctf_sect
));
372 memcpy (&arci
->ctfi_strsect
, strsect
, sizeof (struct ctf_sect
));
373 arci
->ctfi_free_symsect
= 0;
378 /* Open a CTF archive or dictionary from data in a buffer (which the caller must
379 preserve until ctf_arc_close() time). Returns the archive, or NULL and an
380 error in *err (if not NULL). */
382 ctf_arc_bufopen (const ctf_sect_t
*ctfsect
, const ctf_sect_t
*symsect
,
383 const ctf_sect_t
*strsect
, int *errp
)
385 struct ctf_archive
*arc
= NULL
;
387 ctf_file_t
*fp
= NULL
;
389 if (ctfsect
->cts_size
> sizeof (uint64_t) &&
390 ((*(uint64_t *) ctfsect
->cts_data
) == CTFA_MAGIC
))
392 /* The archive is mmappable, so this operation is trivial. */
395 arc
= (struct ctf_archive
*) ctfsect
->cts_data
;
400 if ((fp
= ctf_bufopen (ctfsect
, symsect
, strsect
, errp
)) == NULL
)
402 ctf_dprintf ("ctf_internal_open(): cannot open CTF: %s\n",
407 return ctf_new_archive_internal (is_archive
, arc
, fp
, symsect
, strsect
,
411 /* Open a CTF archive. Returns the archive, or NULL and an error in *err (if
414 ctf_arc_open_internal (const char *filename
, int *errp
)
419 struct ctf_archive
*arc
; /* (Actually the whole file.) */
422 if ((fd
= open (filename
, O_RDONLY
)) < 0)
424 errmsg
= "ctf_arc_open(): cannot open %s: %s\n";
427 if (fstat (fd
, &s
) < 0)
429 errmsg
= "ctf_arc_open(): cannot stat %s: %s\n";
433 if ((arc
= arc_mmap_file (fd
, s
.st_size
)) == NULL
)
435 errmsg
= "ctf_arc_open(): Cannot read in %s: %s\n";
439 if (le64toh (arc
->ctfa_magic
) != CTFA_MAGIC
)
441 errmsg
= "ctf_arc_open(): Invalid magic number";
446 /* This horrible hack lets us know how much to unmap when the file is
447 closed. (We no longer need the magic number, and the mapping
449 arc
->ctfa_magic
= s
.st_size
;
454 arc_mmap_unmap (arc
, s
.st_size
, NULL
);
460 ctf_dprintf (errmsg
, filename
, errno
< ECTF_BASE
? strerror (errno
) :
465 /* Close an archive. */
467 ctf_arc_close_internal (struct ctf_archive
*arc
)
472 /* See the comment in ctf_arc_open(). */
473 arc_mmap_unmap (arc
, arc
->ctfa_magic
, NULL
);
476 /* Public entry point: close an archive, or CTF file. */
478 ctf_arc_close (ctf_archive_t
*arc
)
483 if (arc
->ctfi_is_archive
)
484 ctf_arc_close_internal (arc
->ctfi_archive
);
486 ctf_file_close (arc
->ctfi_file
);
487 if (arc
->ctfi_free_symsect
)
488 free ((void *) arc
->ctfi_symsect
.cts_data
);
489 free (arc
->ctfi_data
);
490 if (arc
->ctfi_bfd_close
)
491 arc
->ctfi_bfd_close (arc
);
495 /* Return the ctf_file_t with the given name, or NULL if none, setting 'err' if
496 non-NULL. A name of NULL means to open the default file. */
498 ctf_arc_open_by_name_internal (const struct ctf_archive
*arc
,
499 const ctf_sect_t
*symsect
,
500 const ctf_sect_t
*strsect
,
501 const char *name
, int *errp
)
503 struct ctf_archive_modent
*modent
;
504 const char *search_nametbl
;
507 name
= _CTF_SECTION
; /* The default name. */
509 ctf_dprintf ("ctf_arc_open_by_name(%s): opening\n", name
);
511 modent
= (ctf_archive_modent_t
*) ((char *) arc
512 + sizeof (struct ctf_archive
));
514 search_nametbl
= (const char *) arc
+ le64toh (arc
->ctfa_names
);
515 modent
= bsearch_r (name
, modent
, le64toh (arc
->ctfa_nfiles
),
516 sizeof (struct ctf_archive_modent
),
517 search_modent_by_name
, (void *) search_nametbl
);
519 /* This is actually a common case and normal operation: no error
524 *errp
= ECTF_ARNNAME
;
528 return ctf_arc_open_by_offset (arc
, symsect
, strsect
,
529 le64toh (modent
->ctf_offset
), errp
);
532 /* Return the ctf_file_t with the given name, or NULL if none, setting 'err' if
533 non-NULL. A name of NULL means to open the default file.
535 Use the specified string and symbol table sections.
537 Public entry point. */
539 ctf_arc_open_by_name_sections (const ctf_archive_t
*arc
,
540 const ctf_sect_t
*symsect
,
541 const ctf_sect_t
*strsect
,
545 if (arc
->ctfi_is_archive
)
548 ret
= ctf_arc_open_by_name_internal (arc
->ctfi_archive
, symsect
, strsect
,
551 ret
->ctf_archive
= (ctf_archive_t
*) arc
;
555 if ((name
!= NULL
) && (strcmp (name
, _CTF_SECTION
) != 0))
558 *errp
= ECTF_ARNNAME
;
561 arc
->ctfi_file
->ctf_archive
= (ctf_archive_t
*) arc
;
563 /* Bump the refcount so that the user can ctf_file_close() it. */
564 arc
->ctfi_file
->ctf_refcnt
++;
565 return arc
->ctfi_file
;
568 /* Return the ctf_file_t with the given name, or NULL if none, setting 'err' if
569 non-NULL. A name of NULL means to open the default file.
571 Public entry point. */
573 ctf_arc_open_by_name (const ctf_archive_t
*arc
, const char *name
, int *errp
)
575 const ctf_sect_t
*symsect
= &arc
->ctfi_symsect
;
576 const ctf_sect_t
*strsect
= &arc
->ctfi_strsect
;
578 if (symsect
->cts_name
== NULL
)
580 if (strsect
->cts_name
== NULL
)
583 return ctf_arc_open_by_name_sections (arc
, symsect
, strsect
, name
, errp
);
586 /* Return the ctf_file_t at the given ctfa_ctfs-relative offset, or NULL if
587 none, setting 'err' if non-NULL. */
589 ctf_arc_open_by_offset (const struct ctf_archive
*arc
,
590 const ctf_sect_t
*symsect
,
591 const ctf_sect_t
*strsect
, size_t offset
,
597 ctf_dprintf ("ctf_arc_open_by_offset(%lu): opening\n", (unsigned long) offset
);
599 memset (&ctfsect
, 0, sizeof (ctf_sect_t
));
601 offset
+= le64toh (arc
->ctfa_ctfs
);
603 ctfsect
.cts_name
= _CTF_SECTION
;
604 ctfsect
.cts_size
= le64toh (*((uint64_t *) ((char *) arc
+ offset
)));
605 ctfsect
.cts_entsize
= 1;
606 ctfsect
.cts_data
= (void *) ((char *) arc
+ offset
+ sizeof (uint64_t));
607 fp
= ctf_bufopen (&ctfsect
, symsect
, strsect
, errp
);
609 ctf_setmodel (fp
, le64toh (arc
->ctfa_model
));
613 /* Raw iteration over all CTF files in an archive. We pass the raw data for all
614 CTF files in turn to the specified callback function. */
616 ctf_archive_raw_iter_internal (const struct ctf_archive
*arc
,
617 ctf_archive_raw_member_f
*func
, void *data
)
621 struct ctf_archive_modent
*modent
;
624 modent
= (ctf_archive_modent_t
*) ((char *) arc
625 + sizeof (struct ctf_archive
));
626 nametbl
= (((const char *) arc
) + le64toh (arc
->ctfa_names
));
628 for (i
= 0; i
< le64toh (arc
->ctfa_nfiles
); i
++)
633 name
= &nametbl
[le64toh (modent
[i
].name_offset
)];
634 fp
= ((char *) arc
+ le64toh (arc
->ctfa_ctfs
)
635 + le64toh (modent
[i
].ctf_offset
));
637 if ((rc
= func (name
, (void *) (fp
+ sizeof (uint64_t)),
638 le64toh (*((uint64_t *) fp
)), data
)) != 0)
644 /* Raw iteration over all CTF files in an archive: public entry point.
646 Returns -EINVAL if not supported for this sort of archive. */
648 ctf_archive_raw_iter (const ctf_archive_t
*arc
,
649 ctf_archive_raw_member_f
* func
, void *data
)
651 if (arc
->ctfi_is_archive
)
652 return ctf_archive_raw_iter_internal (arc
->ctfi_archive
, func
, data
);
654 return -EINVAL
; /* Not supported. */
657 /* Iterate over all CTF files in an archive. We pass all CTF files in turn to
658 the specified callback function. */
660 ctf_archive_iter_internal (const ctf_archive_t
*wrapper
,
661 const struct ctf_archive
*arc
,
662 const ctf_sect_t
*symsect
,
663 const ctf_sect_t
*strsect
,
664 ctf_archive_member_f
*func
, void *data
)
669 struct ctf_archive_modent
*modent
;
672 modent
= (ctf_archive_modent_t
*) ((char *) arc
673 + sizeof (struct ctf_archive
));
674 nametbl
= (((const char *) arc
) + le64toh (arc
->ctfa_names
));
676 for (i
= 0; i
< le64toh (arc
->ctfa_nfiles
); i
++)
680 name
= &nametbl
[le64toh (modent
[i
].name_offset
)];
681 if ((f
= ctf_arc_open_by_name_internal (arc
, symsect
, strsect
,
685 f
->ctf_archive
= (ctf_archive_t
*) wrapper
;
686 if ((rc
= func (f
, name
, data
)) != 0)
697 /* Iterate over all CTF files in an archive: public entry point. We pass all
698 CTF files in turn to the specified callback function. */
700 ctf_archive_iter (const ctf_archive_t
*arc
, ctf_archive_member_f
*func
,
703 const ctf_sect_t
*symsect
= &arc
->ctfi_symsect
;
704 const ctf_sect_t
*strsect
= &arc
->ctfi_strsect
;
706 if (symsect
->cts_name
== NULL
)
708 if (strsect
->cts_name
== NULL
)
711 if (arc
->ctfi_is_archive
)
712 return ctf_archive_iter_internal (arc
, arc
->ctfi_archive
, symsect
, strsect
,
715 return func (arc
->ctfi_file
, _CTF_SECTION
, data
);
719 /* Map the header in. Only used on new, empty files. */
720 static void *arc_mmap_header (int fd
, size_t headersz
)
723 if ((hdr
= mmap (NULL
, headersz
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
,
729 /* mmap() the whole file, for reading only. (Map it writably, but privately: we
730 need to modify the region, but don't need anyone else to see the
732 static void *arc_mmap_file (int fd
, size_t size
)
735 if ((arc
= mmap (NULL
, size
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
,
736 fd
, 0)) == MAP_FAILED
)
741 /* Persist the header to disk. */
742 static int arc_mmap_writeout (int fd _libctf_unused_
, void *header
,
743 size_t headersz
, const char **errmsg
)
745 if (msync (header
, headersz
, MS_ASYNC
) < 0)
748 *errmsg
= "arc_mmap_writeout(): Cannot sync after writing to %s: %s\n";
754 /* Unmap the region. */
755 static int arc_mmap_unmap (void *header
, size_t headersz
, const char **errmsg
)
757 if (munmap (header
, headersz
) < 0)
760 *errmsg
= "arc_mmap_munmap(): Cannot unmap after writing to %s: %s\n";
766 /* Map the header in. Only used on new, empty files. */
767 static void *arc_mmap_header (int fd _libctf_unused_
, size_t headersz
)
770 if ((hdr
= malloc (headersz
)) == NULL
)
775 /* Pull in the whole file, for reading only. We assume the current file
776 position is at the start of the file. */
777 static void *arc_mmap_file (int fd
, size_t size
)
781 if ((data
= malloc (size
)) == NULL
)
784 if (ctf_pread (fd
, data
, size
, 0) < 0)
792 /* Persist the header to disk. */
793 static int arc_mmap_writeout (int fd
, void *header
, size_t headersz
,
798 char *data
= (char *) header
;
799 ssize_t count
= headersz
;
801 if ((lseek (fd
, 0, SEEK_SET
)) < 0)
804 *errmsg
= "arc_mmap_writeout(): Cannot seek while writing header to "
811 if ((len
= write (fd
, data
, count
)) < 0)
814 *errmsg
= "arc_mmap_writeout(): Cannot write header to %s: %s\n";
821 if (len
== 0) /* EOF. */
830 /* Unmap the region. */
831 static int arc_mmap_unmap (void *header
, size_t headersz _libctf_unused_
,
832 const char **errmsg _libctf_unused_
)
This page took 0.046129 seconds and 4 git commands to generate.