90cd020b781bdd23d43ebd8c721fce46db5e36bb
2 Copyright (C) 2019 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 /* bsearch() internal state. */
48 static __thread
char *search_nametbl
;
50 /* Write out a CTF archive. The entries in CTF_FILES are referenced by name:
51 the names are passed in the names array, which must have CTF_FILES entries.
53 Returns 0 on success, or an errno, or an ECTF_* value. */
55 ctf_arc_write (const char *file
, ctf_file_t
** ctf_files
, size_t ctf_file_cnt
,
56 const char **names
, size_t threshold
)
59 struct ctf_archive
*archdr
;
65 size_t ctf_startoffs
; /* Start of the section we are working over. */
66 char *nametbl
= NULL
; /* The name table. */
69 struct ctf_archive_modent
*modent
;
71 ctf_dprintf ("Writing archive %s with %zi files\n", file
, ctf_file_cnt
);
73 if ((fd
= open (file
, O_RDWR
| O_CREAT
| O_TRUNC
| O_CLOEXEC
, 0666)) < 0)
75 errmsg
= "ctf_arc_write(): cannot create %s: %s\n";
79 /* Figure out the size of the mmap()ed header, including the
80 ctf_archive_modent array. We assume that all of this needs no
81 padding: a likely assumption, given that it's all made up of
83 headersz
= sizeof (struct ctf_archive
)
84 + (ctf_file_cnt
* sizeof (uint64_t) * 2);
85 ctf_dprintf ("headersz is %zi\n", headersz
);
87 /* From now on we work in two pieces: an mmap()ed region from zero up to the
88 headersz, and a region updated via write() starting after that, containing
89 all the tables. Platforms that do not support mmap() just use write(). */
90 ctf_startoffs
= headersz
;
91 if (lseek (fd
, ctf_startoffs
- 1, SEEK_SET
) < 0)
93 errmsg
= "ctf_arc_write(): cannot extend file while writing %s: %s\n";
97 if (write (fd
, &dummy
, 1) < 0)
99 errmsg
= "ctf_arc_write(): cannot extend file while writing %s: %s\n";
103 if ((archdr
= arc_mmap_header (fd
, headersz
)) == NULL
)
105 errmsg
= "ctf_arc_write(): Cannot mmap() %s: %s\n";
109 /* Fill in everything we can, which is everything other than the name
111 archdr
->ctfa_magic
= htole64 (CTFA_MAGIC
);
112 archdr
->ctfa_nfiles
= htole64 (ctf_file_cnt
);
113 archdr
->ctfa_ctfs
= htole64 (ctf_startoffs
);
115 /* We could validate that all CTF files have the same data model, but
116 since any reasonable construction process will be building things of
117 only one bitness anyway, this is pretty pointless, so just use the
118 model of the first CTF file for all of them. (It *is* valid to
119 create an empty archive: the value of ctfa_model is irrelevant in
120 this case, but we must be sure not to dereference uninitialized
123 if (ctf_file_cnt
> 0)
124 archdr
->ctfa_model
= htole64 (ctf_getmodel (ctf_files
[0]));
126 /* Now write out the CTFs: ctf_archive_modent array via the mapping,
127 ctfs via write(). The names themselves have not been written yet: we
128 track them in a local strtab until the time is right, and sort the
129 modents array after construction.
131 The name table is not sorted. */
133 for (i
= 0, namesz
= 0; i
< le64toh (archdr
->ctfa_nfiles
); i
++)
134 namesz
+= strlen (names
[i
]) + 1;
136 nametbl
= malloc (namesz
);
139 errmsg
= "Error writing named CTF to %s: %s\n";
143 for (i
= 0, namesz
= 0,
144 modent
= (ctf_archive_modent_t
*) ((char *) archdr
145 + sizeof (struct ctf_archive
));
146 i
< le64toh (archdr
->ctfa_nfiles
); i
++)
150 strcpy (&nametbl
[namesz
], names
[i
]);
152 off
= arc_write_one_ctf (ctf_files
[i
], fd
, threshold
);
153 if ((off
< 0) && (off
> -ECTF_BASE
))
155 errmsg
= "ctf_arc_write(): Cannot determine file "
156 "position while writing %s: %s";
161 errmsg
= "ctf_arc_write(): Cannot write CTF file to %s: %s\n";
166 modent
->name_offset
= htole64 (namesz
);
167 modent
->ctf_offset
= htole64 (off
- ctf_startoffs
);
168 namesz
+= strlen (names
[i
]) + 1;
172 ctf_qsort_r ((ctf_archive_modent_t
*) ((char *) archdr
173 + sizeof (struct ctf_archive
)),
174 le64toh (archdr
->ctfa_nfiles
),
175 sizeof (struct ctf_archive_modent
), sort_modent_by_name
,
178 /* Now the name table. */
180 if ((nameoffs
= lseek (fd
, 0, SEEK_CUR
)) < 0)
182 errmsg
= "ctf_arc_write(): Cannot get current file position "
186 archdr
->ctfa_names
= htole64 (nameoffs
);
191 if ((len
= write (fd
, np
, namesz
)) < 0)
193 errmsg
= "ctf_arc_write(): Cannot write name table in %s: %s\n";
201 if (arc_mmap_writeout (fd
, archdr
, headersz
, &errmsg
) < 0)
203 if (arc_mmap_unmap (archdr
, headersz
, &errmsg
) < 0)
207 errmsg
= "ctf_arc_write(): Cannot close after writing to %s: %s\n";
216 arc_mmap_unmap (archdr
, headersz
, NULL
);
222 ctf_dprintf (errmsg
, file
, errno
< ECTF_BASE
? strerror (errno
) :
227 /* Write one CTF file out. Return the file position of the written file (or
228 rather, of the file-size uint64_t that precedes it): negative return is a
229 negative errno or ctf_errno value. On error, the file position may no longer
230 be at the end of the file. */
232 arc_write_one_ctf (ctf_file_t
* f
, int fd
, size_t threshold
)
238 int (*writefn
) (ctf_file_t
* fp
, int fd
);
240 if ((off
= lseek (fd
, 0, SEEK_CUR
)) < 0)
243 if (f
->ctf_size
> threshold
)
244 writefn
= ctf_compress_write
;
248 /* This zero-write turns into the size in a moment. */
249 ctfsz_len
= sizeof (ctfsz
);
250 ctfszp
= (char *) &ctfsz
;
251 while (ctfsz_len
> 0)
253 ssize_t writelen
= write (fd
, ctfszp
, ctfsz_len
);
256 ctfsz_len
-= writelen
;
260 if (writefn (f
, fd
) != 0)
261 return f
->ctf_errno
* -1;
263 if ((end_off
= lseek (fd
, 0, SEEK_CUR
)) < 0)
265 ctfsz
= htole64 (end_off
- off
);
267 if ((lseek (fd
, off
, SEEK_SET
)) < 0)
271 ctfsz_len
= sizeof (ctfsz
);
272 ctfszp
= (char *) &ctfsz
;
273 while (ctfsz_len
> 0)
275 ssize_t writelen
= write (fd
, ctfszp
, ctfsz_len
);
278 ctfsz_len
-= writelen
;
282 end_off
= LCTF_ALIGN_OFFS (end_off
, 8);
283 if ((lseek (fd
, end_off
, SEEK_SET
)) < 0)
289 /* qsort() function to sort the array of struct ctf_archive_modents into
290 ascending name order. */
292 sort_modent_by_name (const void *one
, const void *two
, void *n
)
294 const struct ctf_archive_modent
*a
= one
;
295 const struct ctf_archive_modent
*b
= two
;
298 return strcmp (&nametbl
[le64toh (a
->name_offset
)],
299 &nametbl
[le64toh (b
->name_offset
)]);
302 /* bsearch() function to search for a given name in the sorted array of struct
303 ctf_archive_modents. */
305 search_modent_by_name (const void *key
, const void *ent
)
308 const struct ctf_archive_modent
*v
= ent
;
310 return strcmp (k
, &search_nametbl
[le64toh (v
->name_offset
)]);
313 /* A trivial wrapper: open a CTF archive, from data in a buffer (which the
314 caller must preserve until ctf_arc_close() time). Returns the archive, or
315 NULL and an error in *err (if not NULL). */
317 ctf_arc_bufopen (const void *buf
, size_t size _libctf_unused_
, int *errp
)
319 struct ctf_archive
*arc
= (struct ctf_archive
*) buf
;
321 if (le64toh (arc
->ctfa_magic
) != CTFA_MAGIC
)
330 /* Open a CTF archive. Returns the archive, or NULL and an error in *err (if
333 ctf_arc_open_internal (const char *filename
, int *errp
)
338 struct ctf_archive
*arc
; /* (Actually the whole file.) */
341 if ((fd
= open (filename
, O_RDONLY
)) < 0)
343 errmsg
= "ctf_arc_open(): cannot open %s: %s\n";
346 if (fstat (fd
, &s
) < 0)
348 errmsg
= "ctf_arc_open(): cannot stat %s: %s\n";
352 if ((arc
= arc_mmap_file (fd
, s
.st_size
)) == NULL
)
354 errmsg
= "ctf_arc_open(): Cannot read in %s: %s\n";
358 if (le64toh (arc
->ctfa_magic
) != CTFA_MAGIC
)
360 errmsg
= "ctf_arc_open(): Invalid magic number";
365 /* This horrible hack lets us know how much to unmap when the file is
366 closed. (We no longer need the magic number, and the mapping
368 arc
->ctfa_magic
= s
.st_size
;
373 arc_mmap_unmap (arc
, s
.st_size
, NULL
);
379 ctf_dprintf (errmsg
, filename
, errno
< ECTF_BASE
? strerror (errno
) :
384 /* Close an archive. */
386 ctf_arc_close_internal (struct ctf_archive
*arc
)
391 /* See the comment in ctf_arc_open(). */
392 arc_mmap_unmap (arc
, arc
->ctfa_magic
, NULL
);
395 /* Public entry point: close an archive, or CTF file. */
397 ctf_arc_close (ctf_archive_t
*arc
)
402 if (arc
->ctfi_is_archive
)
403 ctf_arc_close_internal (arc
->ctfi_archive
);
405 ctf_file_close (arc
->ctfi_file
);
406 free ((void *) arc
->ctfi_symsect
.cts_data
);
407 free ((void *) arc
->ctfi_strsect
.cts_data
);
408 free (arc
->ctfi_data
);
412 /* Return the ctf_file_t with the given name, or NULL if none, setting 'err' if
413 non-NULL. A name of NULL means to open the default file. */
415 ctf_arc_open_by_name_internal (const struct ctf_archive
*arc
,
416 const ctf_sect_t
*symsect
,
417 const ctf_sect_t
*strsect
,
418 const char *name
, int *errp
)
420 struct ctf_archive_modent
*modent
;
423 name
= _CTF_SECTION
; /* The default name. */
425 ctf_dprintf ("ctf_arc_open_by_name(%s): opening\n", name
);
427 modent
= (ctf_archive_modent_t
*) ((char *) arc
428 + sizeof (struct ctf_archive
));
430 search_nametbl
= (char *) arc
+ le64toh (arc
->ctfa_names
);
431 modent
= bsearch (name
, modent
, le64toh (arc
->ctfa_nfiles
),
432 sizeof (struct ctf_archive_modent
),
433 search_modent_by_name
);
435 /* This is actually a common case and normal operation: no error
440 *errp
= ECTF_ARNNAME
;
444 return ctf_arc_open_by_offset (arc
, symsect
, strsect
,
445 le64toh (modent
->ctf_offset
), errp
);
448 /* Return the ctf_file_t with the given name, or NULL if none, setting 'err' if
449 non-NULL. A name of NULL means to open the default file.
451 Use the specified string and symbol table sections.
453 Public entry point. */
455 ctf_arc_open_by_name_sections (const ctf_archive_t
*arc
,
456 const ctf_sect_t
*symsect
,
457 const ctf_sect_t
*strsect
,
461 if (arc
->ctfi_is_archive
)
464 ret
= ctf_arc_open_by_name_internal (arc
->ctfi_archive
, symsect
, strsect
,
467 ret
->ctf_archive
= (ctf_archive_t
*) arc
;
471 if ((name
!= NULL
) && (strcmp (name
, _CTF_SECTION
) != 0))
474 *errp
= ECTF_ARNNAME
;
477 arc
->ctfi_file
->ctf_archive
= (ctf_archive_t
*) arc
;
479 /* Bump the refcount so that the user can ctf_file_close() it. */
480 arc
->ctfi_file
->ctf_refcnt
++;
481 return arc
->ctfi_file
;
484 /* Return the ctf_file_t with the given name, or NULL if none, setting 'err' if
485 non-NULL. A name of NULL means to open the default file.
487 Public entry point. */
489 ctf_arc_open_by_name (const ctf_archive_t
*arc
, const char *name
, int *errp
)
491 const ctf_sect_t
*symsect
= &arc
->ctfi_symsect
;
492 const ctf_sect_t
*strsect
= &arc
->ctfi_strsect
;
494 if (symsect
->cts_name
== NULL
)
496 if (strsect
->cts_name
== NULL
)
499 return ctf_arc_open_by_name_sections (arc
, symsect
, strsect
, name
, errp
);
502 /* Return the ctf_file_t at the given ctfa_ctfs-relative offset, or NULL if
503 none, setting 'err' if non-NULL. */
505 ctf_arc_open_by_offset (const struct ctf_archive
*arc
,
506 const ctf_sect_t
*symsect
,
507 const ctf_sect_t
*strsect
, size_t offset
,
513 ctf_dprintf ("ctf_arc_open_by_offset(%zi): opening\n", offset
);
515 memset (&ctfsect
, 0, sizeof (ctf_sect_t
));
517 offset
+= le64toh (arc
->ctfa_ctfs
);
519 ctfsect
.cts_name
= _CTF_SECTION
;
520 ctfsect
.cts_size
= le64toh (*((uint64_t *) ((char *) arc
+ offset
)));
521 ctfsect
.cts_entsize
= 1;
522 ctfsect
.cts_data
= (void *) ((char *) arc
+ offset
+ sizeof (uint64_t));
523 fp
= ctf_bufopen (&ctfsect
, symsect
, strsect
, errp
);
525 ctf_setmodel (fp
, le64toh (arc
->ctfa_model
));
529 /* Raw iteration over all CTF files in an archive. We pass the raw data for all
530 CTF files in turn to the specified callback function. */
532 ctf_archive_raw_iter_internal (const struct ctf_archive
*arc
,
533 ctf_archive_raw_member_f
*func
, void *data
)
537 struct ctf_archive_modent
*modent
;
540 modent
= (ctf_archive_modent_t
*) ((char *) arc
541 + sizeof (struct ctf_archive
));
542 nametbl
= (((const char *) arc
) + le64toh (arc
->ctfa_names
));
544 for (i
= 0; i
< le64toh (arc
->ctfa_nfiles
); i
++)
549 name
= &nametbl
[le64toh (modent
[i
].name_offset
)];
550 fp
= ((char *) arc
+ le64toh (arc
->ctfa_ctfs
)
551 + le64toh (modent
[i
].ctf_offset
));
553 if ((rc
= func (name
, (void *) (fp
+ sizeof (uint64_t)),
554 le64toh (*((uint64_t *) fp
)), data
)) != 0)
560 /* Raw iteration over all CTF files in an archive: public entry point.
562 Returns -EINVAL if not supported for this sort of archive. */
564 ctf_archive_raw_iter (const ctf_archive_t
*arc
,
565 ctf_archive_raw_member_f
* func
, void *data
)
567 if (arc
->ctfi_is_archive
)
568 return ctf_archive_raw_iter_internal (arc
->ctfi_archive
, func
, data
);
570 return -EINVAL
; /* Not supported. */
573 /* Iterate over all CTF files in an archive. We pass all CTF files in turn to
574 the specified callback function. */
576 ctf_archive_iter_internal (const ctf_archive_t
*wrapper
,
577 const struct ctf_archive
*arc
,
578 const ctf_sect_t
*symsect
,
579 const ctf_sect_t
*strsect
,
580 ctf_archive_member_f
*func
, void *data
)
585 struct ctf_archive_modent
*modent
;
588 modent
= (ctf_archive_modent_t
*) ((char *) arc
589 + sizeof (struct ctf_archive
));
590 nametbl
= (((const char *) arc
) + le64toh (arc
->ctfa_names
));
592 for (i
= 0; i
< le64toh (arc
->ctfa_nfiles
); i
++)
596 name
= &nametbl
[le64toh (modent
[i
].name_offset
)];
597 if ((f
= ctf_arc_open_by_name_internal (arc
, symsect
, strsect
,
601 f
->ctf_archive
= (ctf_archive_t
*) wrapper
;
602 if ((rc
= func (f
, name
, data
)) != 0)
613 /* Iterate over all CTF files in an archive: public entry point. We pass all
614 CTF files in turn to the specified callback function. */
616 ctf_archive_iter (const ctf_archive_t
*arc
, ctf_archive_member_f
*func
,
619 const ctf_sect_t
*symsect
= &arc
->ctfi_symsect
;
620 const ctf_sect_t
*strsect
= &arc
->ctfi_strsect
;
622 if (symsect
->cts_name
== NULL
)
624 if (strsect
->cts_name
== NULL
)
627 if (arc
->ctfi_is_archive
)
628 return ctf_archive_iter_internal (arc
, arc
->ctfi_archive
, symsect
, strsect
,
631 return func (arc
->ctfi_file
, _CTF_SECTION
, data
);
635 /* Map the header in. Only used on new, empty files. */
636 static void *arc_mmap_header (int fd
, size_t headersz
)
639 if ((hdr
= mmap (NULL
, headersz
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
,
645 /* mmap() the whole file, for reading only. (Map it writably, but privately: we
646 need to modify the region, but don't need anyone else to see the
648 static void *arc_mmap_file (int fd
, size_t size
)
651 if ((arc
= mmap (NULL
, size
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
,
652 fd
, 0)) == MAP_FAILED
)
657 /* Persist the header to disk. */
658 static int arc_mmap_writeout (int fd _libctf_unused_
, void *header
,
659 size_t headersz
, const char **errmsg
)
661 if (msync (header
, headersz
, MS_ASYNC
) < 0)
664 *errmsg
= "arc_mmap_writeout(): Cannot sync after writing to %s: %s\n";
670 /* Unmap the region. */
671 static int arc_mmap_unmap (void *header
, size_t headersz
, const char **errmsg
)
673 if (munmap (header
, headersz
) < 0)
676 *errmsg
= "arc_mmap_munmap(): Cannot unmap after writing to %s: %s\n";
682 /* Map the header in. Only used on new, empty files. */
683 static void *arc_mmap_header (int fd
, size_t headersz
)
686 if ((hdr
= malloc (headersz
)) == NULL
)
691 /* Pull in the whole file, for reading only. We assume the current file
692 position is at the start of the file. */
693 static void *arc_mmap_file (int fd
, size_t size
)
697 if ((data
= malloc (size
)) == NULL
)
700 if (ctf_pread (fd
, data
, size
, 0) < 0)
708 /* Persist the header to disk. */
709 static int arc_mmap_writeout (int fd
, void *header
, size_t headersz
,
714 char *data
= (char *) header
;
715 ssize_t count
= headersz
;
717 if ((lseek (fd
, 0, SEEK_SET
)) < 0)
720 *errmsg
= "arc_mmap_writeout(): Cannot seek while writing header to "
727 if ((len
= write (fd
, data
, count
)) < 0)
730 *errmsg
= "arc_mmap_writeout(): Cannot write header to %s: %s\n";
737 if (len
== 0) /* EOF. */
746 /* Unmap the region. */
747 static int arc_mmap_unmap (void *header
, size_t headersz _libctf_unused_
,
748 const char **errmsg _libctf_unused_
)
This page took 0.047809 seconds and 4 git commands to generate.