2 SPDX-License-Identifier: GPL-2.0-only
4 Copyright (C) 2019 Arnaldo Carvalho de Melo <acme@redhat.com>
23 bool ctf__ignore_symtab_function(const GElf_Sym
*sym
, const char *sym_name
)
25 return (!elf_sym__is_local_function(sym
) ||
26 elf_sym__visibility(sym
) != STV_DEFAULT
||
28 memcmp(sym_name
, "__libc_csu_",
29 sizeof("__libc_csu_") - 1) == 0);
32 bool ctf__ignore_symtab_object(const GElf_Sym
*sym
, const char *sym_name
)
34 return (!elf_sym__is_local_object(sym
) || sym
->st_size
== 0 ||
35 elf_sym__visibility(sym
) != STV_DEFAULT
||
36 strchr(sym_name
, '.') != NULL
);
39 uint16_t ctf__get16(struct ctf
*ctf
, uint16_t *p
)
44 val
= ((val
>> 8) | (val
<< 8));
48 uint32_t ctf__get32(struct ctf
*ctf
, uint32_t *p
)
54 ((val
>> 8) & 0x0000ff00) |
55 ((val
<< 8) & 0x00ff0000) |
60 void ctf__put16(struct ctf
*ctf
, uint16_t *p
, uint16_t val
)
63 val
= ((val
>> 8) | (val
<< 8));
67 void ctf__put32(struct ctf
*ctf
, uint32_t *p
, uint32_t val
)
71 ((val
>> 8) & 0x0000ff00) |
72 ((val
<< 8) & 0x00ff0000) |
77 static int ctf__decompress(struct ctf
*ctf
, void *orig_buf
, size_t orig_size
)
79 struct ctf_header
*hp
= orig_buf
;
85 len
= (ctf__get32(ctf
, &hp
->ctf_str_off
) +
86 ctf__get32(ctf
, &hp
->ctf_str_len
));
87 new = malloc(len
+ sizeof(*hp
));
89 fprintf(stderr
, "CTF decompression allocation failure.\n");
92 memcpy(new, hp
, sizeof(*hp
));
94 memset(&state
, 0, sizeof(state
));
95 state
.next_in
= (Bytef
*) (hp
+ 1);
96 state
.avail_in
= orig_size
- sizeof(*hp
);
97 state
.next_out
= new + sizeof(*hp
);
98 state
.avail_out
= len
;
100 if (inflateInit(&state
) != Z_OK
) {
101 err_str
= "struct ctf decompression inflateInit failure.";
105 if (inflate(&state
, Z_FINISH
) != Z_STREAM_END
) {
106 err_str
= "struct ctf decompression inflate failure.";
110 if (inflateEnd(&state
) != Z_OK
) {
111 err_str
= "struct ctf decompression inflateEnd failure.";
115 if (state
.total_out
!= len
) {
116 err_str
= "struct ctf decompression truncation error.";
121 ctf
->size
= len
+ sizeof(*hp
);
126 fputs(err_str
, stderr
);
131 int ctf__load(struct ctf
*ctf
)
135 Elf_Scn
*sec
= elf_section_by_name(ctf
->elf
, &shdr
, ".SUNW_ctf", NULL
);
140 Elf_Data
*data
= elf_getdata(sec
, NULL
);
142 fprintf(stderr
, "%s: cannot get data of CTF section.\n",
147 struct ctf_header
*hp
= data
->d_buf
;
148 size_t orig_size
= data
->d_size
;
150 if (hp
->ctf_version
!= CTF_VERSION
)
154 if (hp
->ctf_magic
== CTF_MAGIC
)
156 else if (hp
->ctf_magic
== CTF_MAGIC_SWAP
)
161 if (!(hp
->ctf_flags
& CTF_FLAGS_COMPR
)) {
163 ctf
->buf
= malloc(orig_size
);
164 if (ctf
->buf
!= NULL
) {
165 memcpy(ctf
->buf
, hp
, orig_size
);
166 ctf
->size
= orig_size
;
170 err
= ctf__decompress(ctf
, hp
, orig_size
);
177 struct ctf
*ctf__new(const char *filename
, Elf
*elf
)
179 struct ctf
*ctf
= zalloc(sizeof(*ctf
));
182 ctf
->filename
= strdup(filename
);
183 if (ctf
->filename
== NULL
)
191 ctf
->in_fd
= open(filename
, O_RDONLY
);
193 goto out_delete_filename
;
195 if (elf_version(EV_CURRENT
) == EV_NONE
) {
196 fprintf(stderr
, "%s: cannot set libelf version.\n",
201 ctf
->elf
= elf_begin(ctf
->in_fd
, ELF_C_READ_MMAP
, NULL
);
203 fprintf(stderr
, "%s: cannot read %s ELF file.\n",
209 if (gelf_getehdr(ctf
->elf
, &ctf
->ehdr
) == NULL
) {
211 fprintf(stderr
, "%s: cannot get elf header.\n", __func__
);
215 switch (ctf
->ehdr
.e_ident
[EI_CLASS
]) {
216 case ELFCLASS32
: ctf
->wordsize
= 4; break;
217 case ELFCLASS64
: ctf
->wordsize
= 8; break;
218 default: ctf
->wordsize
= 0; break;
230 zfree(&ctf
->filename
);
236 void ctf__delete(struct ctf
*ctf
)
239 if (ctf
->in_fd
!= -1) {
243 __gobuffer__delete(&ctf
->objects
);
244 __gobuffer__delete(&ctf
->types
);
245 __gobuffer__delete(&ctf
->funcs
);
246 elf_symtab__delete(ctf
->symtab
);
247 zfree(&ctf
->filename
);
253 char *ctf__string(struct ctf
*ctf
, uint32_t ref
)
255 struct ctf_header
*hp
= ctf
->buf
;
256 uint32_t off
= CTF_REF_OFFSET(ref
);
259 if (CTF_REF_TBL_ID(ref
) != CTF_STR_TBL_ID_0
)
260 return "(external ref)";
262 if (off
>= ctf__get32(ctf
, &hp
->ctf_str_len
))
263 return "(ref out-of-bounds)";
265 if ((off
+ ctf__get32(ctf
, &hp
->ctf_str_off
)) >= ctf
->size
)
266 return "(string table truncated)";
268 name
= ((char *)(hp
+ 1) + ctf__get32(ctf
, &hp
->ctf_str_off
) + off
);
270 return name
[0] == '\0' ? NULL
: name
;
273 void *ctf__get_buffer(struct ctf
*ctf
)
278 size_t ctf__get_size(struct ctf
*ctf
)
283 int ctf__load_symtab(struct ctf
*ctf
)
285 ctf
->symtab
= elf_symtab__new(".symtab", ctf
->elf
);
286 return ctf
->symtab
== NULL
? -1 : 0;
289 void ctf__set_strings(struct ctf
*ctf
, struct strings
*strings
)
291 ctf
->strings
= strings
;
294 uint32_t ctf__add_base_type(struct ctf
*ctf
, uint32_t name
, uint16_t size
)
296 struct ctf_full_type t
;
298 t
.base
.ctf_name
= name
;
299 t
.base
.ctf_info
= CTF_INFO_ENCODE(CTF_TYPE_KIND_INT
, 0, 0);
300 t
.base
.ctf_size
= size
;
301 t
.ctf_size_high
= CTF_TYPE_INT_ENCODE(0, 0, size
);
303 gobuffer__add(&ctf
->types
, &t
, sizeof(t
) - sizeof(uint32_t));
304 return ++ctf
->type_index
;
307 uint32_t ctf__add_short_type(struct ctf
*ctf
, uint16_t kind
, uint16_t type
, uint32_t name
)
309 struct ctf_short_type t
;
312 t
.ctf_info
= CTF_INFO_ENCODE(kind
, 0, 0);
315 gobuffer__add(&ctf
->types
, &t
, sizeof(t
));
316 return ++ctf
->type_index
;
319 uint32_t ctf__add_fwd_decl(struct ctf
*ctf
, uint32_t name
)
321 return ctf__add_short_type(ctf
, CTF_TYPE_KIND_FWD
, 0, name
);
324 uint32_t ctf__add_array(struct ctf
*ctf
, uint16_t type
, uint16_t index_type
, uint32_t nelems
)
327 struct ctf_short_type t
;
331 array
.t
.ctf_name
= 0;
332 array
.t
.ctf_info
= CTF_INFO_ENCODE(CTF_TYPE_KIND_ARR
, 0, 0);
333 array
.t
.ctf_size
= 0;
334 array
.a
.ctf_array_type
= type
;
335 array
.a
.ctf_array_index_type
= index_type
;
336 array
.a
.ctf_array_nelems
= nelems
;
338 gobuffer__add(&ctf
->types
, &array
, sizeof(array
));
339 return ++ctf
->type_index
;
342 void ctf__add_short_member(struct ctf
*ctf
, uint32_t name
, uint16_t type
,
343 uint16_t offset
, int64_t *position
)
345 struct ctf_short_member m
= {
346 .ctf_member_name
= name
,
347 .ctf_member_type
= type
,
348 .ctf_member_offset
= offset
,
351 memcpy(gobuffer__ptr(&ctf
->types
, *position
), &m
, sizeof(m
));
352 *position
+= sizeof(m
);
355 void ctf__add_full_member(struct ctf
*ctf
, uint32_t name
, uint16_t type
,
356 uint64_t offset
, int64_t *position
)
358 struct ctf_full_member m
= {
359 .ctf_member_name
= name
,
360 .ctf_member_type
= type
,
361 .ctf_member_offset_high
= offset
>> 32,
362 .ctf_member_offset_low
= offset
& 0xffffffffl
,
365 memcpy(gobuffer__ptr(&ctf
->types
, *position
), &m
, sizeof(m
));
366 *position
+= sizeof(m
);
369 uint32_t ctf__add_struct(struct ctf
*ctf
, uint16_t kind
, uint32_t name
,
370 uint64_t size
, uint16_t nr_members
, int64_t *position
)
372 const bool is_short
= size
< CTF_SHORT_MEMBER_LIMIT
;
373 uint32_t members_len
= ((is_short
? sizeof(struct ctf_short_member
) :
374 sizeof(struct ctf_full_member
)) *
376 struct ctf_full_type t
;
379 t
.base
.ctf_name
= name
;
380 t
.base
.ctf_info
= CTF_INFO_ENCODE(kind
, nr_members
, 0);
382 len
= sizeof(t
.base
);
383 t
.base
.ctf_size
= size
;
386 t
.base
.ctf_size
= 0xffff;
387 t
.ctf_size_high
= size
>> 32;
388 t
.ctf_size_low
= size
& 0xffffffff;
391 gobuffer__add(&ctf
->types
, &t
, len
);
392 *position
= gobuffer__allocate(&ctf
->types
, members_len
);
393 return ++ctf
->type_index
;
396 void ctf__add_parameter(struct ctf
*ctf
, uint16_t type
, int64_t *position
)
398 uint16_t *parm
= gobuffer__ptr(&ctf
->types
, *position
);
401 *position
+= sizeof(*parm
);
404 uint32_t ctf__add_function_type(struct ctf
*ctf
, uint16_t type
, uint16_t nr_parms
,
405 bool varargs
, int64_t *position
)
407 struct ctf_short_type t
;
408 int len
= sizeof(uint16_t) * (nr_parms
+ !!varargs
);
411 * Round up to next multiple of 4 to maintain 32-bit alignment.
417 t
.ctf_info
= CTF_INFO_ENCODE(CTF_TYPE_KIND_FUNC
,
418 nr_parms
+ !!varargs
, 0);
421 gobuffer__add(&ctf
->types
, &t
, sizeof(t
));
422 *position
= gobuffer__allocate(&ctf
->types
, len
);
424 unsigned int pos
= *position
+ (nr_parms
* sizeof(uint16_t));
425 uint16_t *end_of_args
= gobuffer__ptr(&ctf
->types
, pos
);
429 return ++ctf
->type_index
;
432 uint32_t ctf__add_enumeration_type(struct ctf
*ctf
, uint32_t name
, uint16_t size
,
433 uint16_t nr_entries
, int64_t *position
)
435 struct ctf_short_type e
;
438 e
.ctf_info
= CTF_INFO_ENCODE(CTF_TYPE_KIND_ENUM
, nr_entries
, 0);
441 gobuffer__add(&ctf
->types
, &e
, sizeof(e
));
442 *position
= gobuffer__allocate(&ctf
->types
,
443 nr_entries
* sizeof(struct ctf_enum
));
444 return ++ctf
->type_index
;
447 void ctf__add_enumerator(struct ctf
*ctf
, uint32_t name
, uint32_t value
,
450 struct ctf_enum m
= {
451 .ctf_enum_name
= name
,
452 .ctf_enum_val
= value
,
455 memcpy(gobuffer__ptr(&ctf
->types
, *position
), &m
, sizeof(m
));
456 *position
+= sizeof(m
);
459 void ctf__add_function_parameter(struct ctf
*ctf
, uint16_t type
,
462 uint16_t *parm
= gobuffer__ptr(&ctf
->funcs
, *position
);
465 *position
+= sizeof(*parm
);
468 int ctf__add_function(struct ctf
*ctf
, uint16_t type
, uint16_t nr_parms
,
469 bool varargs
, int64_t *position
)
471 struct ctf_short_type func
;
472 int len
= sizeof(uint16_t) * (nr_parms
+ !!varargs
);
475 * Round up to next multiple of 4 to maintain 32-bit alignment.
480 func
.ctf_info
= CTF_INFO_ENCODE(CTF_TYPE_KIND_FUNC
,
481 nr_parms
+ !!varargs
, 0);
482 func
.ctf_type
= type
;
485 * We don't store the name for the function, it comes from the
488 gobuffer__add(&ctf
->funcs
, &func
.ctf_info
,
489 sizeof(func
) - sizeof(func
.ctf_name
));
490 *position
= gobuffer__allocate(&ctf
->funcs
, len
);
492 unsigned int pos
= *position
+ (nr_parms
* sizeof(uint16_t));
493 uint16_t *end_of_args
= gobuffer__ptr(&ctf
->funcs
, pos
);
500 int ctf__add_object(struct ctf
*ctf
, uint16_t type
)
502 return gobuffer__add(&ctf
->objects
, &type
,
503 sizeof(type
)) >= 0 ? 0 : -ENOMEM
;
507 static const void *ctf__compress(void *orig_buf
, unsigned int *size
)
514 .next_in
= (Bytef
*)orig_buf
,
517 unsigned int bf_size
= 0;
519 if (deflateInit(&z
, Z_BEST_COMPRESSION
) != Z_OK
)
522 #define _GOBUFFER__ZCHUNK 16384 * 1024
525 const unsigned int new_bf_size
= bf_size
+ _GOBUFFER__ZCHUNK
;
526 void *nbf
= realloc(bf
, new_bf_size
);
529 goto out_close_and_free
;
532 z
.avail_out
= _GOBUFFER__ZCHUNK
;
533 z
.next_out
= (Bytef
*)bf
+ bf_size
;
534 bf_size
= new_bf_size
;
535 if (deflate(&z
, Z_FULL_FLUSH
) == Z_STREAM_ERROR
)
536 goto out_close_and_free
;
539 "%s: size=%d, bf_size=%d, total_out=%ld, total_in=%ld\n",
540 __func__
, *size
, bf_size
, z
.total_out
, z
.total_in
);
542 } while (z
.total_in
!= *size
);
544 if (deflate(&z
, Z_FINISH
) == Z_STREAM_ERROR
)
545 goto out_close_and_free
;
559 int ctf__encode(struct ctf
*ctf
, uint8_t flags
)
561 struct ctf_header
*hdr
;
566 /* Empty file, nothing to do, so... done! */
567 if (gobuffer__size(&ctf
->types
) == 0)
570 size
= (gobuffer__size(&ctf
->types
) +
571 gobuffer__size(&ctf
->objects
) +
572 gobuffer__size(&ctf
->funcs
) +
573 strings__size(ctf
->strings
));
575 ctf
->size
= sizeof(*hdr
) + size
;
576 ctf
->buf
= malloc(ctf
->size
);
578 if (ctf
->buf
== NULL
) {
579 fprintf(stderr
, "%s: malloc failed!\n", __func__
);
584 memset(hdr
, 0, sizeof(*hdr
));
585 hdr
->ctf_magic
= CTF_MAGIC
;
586 hdr
->ctf_version
= 2;
587 hdr
->ctf_flags
= flags
;
590 hdr
->ctf_object_off
= offset
;
591 offset
+= gobuffer__size(&ctf
->objects
);
592 hdr
->ctf_func_off
= offset
;
593 offset
+= gobuffer__size(&ctf
->funcs
);
594 hdr
->ctf_type_off
= offset
;
595 offset
+= gobuffer__size(&ctf
->types
);
596 hdr
->ctf_str_off
= offset
;
597 hdr
->ctf_str_len
= strings__size(ctf
->strings
);
599 void *payload
= ctf
->buf
+ sizeof(*hdr
);
600 gobuffer__copy(&ctf
->objects
, payload
+ hdr
->ctf_object_off
);
601 gobuffer__copy(&ctf
->funcs
, payload
+ hdr
->ctf_func_off
);
602 gobuffer__copy(&ctf
->types
, payload
+ hdr
->ctf_type_off
);
603 strings__copy(ctf
->strings
, payload
+ hdr
->ctf_str_off
);
605 *(char *)(ctf
->buf
+ sizeof(*hdr
) + hdr
->ctf_str_off
) = '\0';
606 if (flags
& CTF_FLAGS_COMPR
) {
607 bf
= (void *)ctf__compress(ctf
->buf
+ sizeof(*hdr
), &size
);
609 printf("%s: ctf__compress failed!\n", __func__
);
612 void *new_bf
= malloc(sizeof(*hdr
) + size
);
615 memcpy(new_bf
, hdr
, sizeof(*hdr
));
616 memcpy(new_bf
+ sizeof(*hdr
), bf
, size
);
619 size
+= sizeof(*hdr
);
625 printf("\n\ntypes:\n entries: %d\n size: %u"
626 "\nstrings:\n size: %u\ncompressed size: %d\n",
628 gobuffer__size(&ctf
->types
),
629 strings__size(ctf
->strings
), size
);
631 int fd
= open(ctf
->filename
, O_RDWR
);
633 fprintf(stderr
, "Cannot open %s\n", ctf
->filename
);
637 if (elf_version(EV_CURRENT
) == EV_NONE
) {
638 fprintf(stderr
, "Cannot set libelf version.\n");
642 Elf
*elf
= elf_begin(fd
, ELF_C_RDWR
, NULL
);
644 fprintf(stderr
, "Cannot update ELF file.\n");
648 elf_flagelf(elf
, ELF_C_SET
, ELF_F_DIRTY
);
651 GElf_Ehdr
*ehdr
= gelf_getehdr(elf
, &ehdr_mem
);
653 fprintf(stderr
, "%s: elf_getehdr failed.\n", __func__
);
658 * First we look if there was already a .SUNW_ctf section to overwrite.
660 Elf_Data
*data
= NULL
;
666 elf_getshdrstrndx(elf
, &strndx
);
668 while ((scn
= elf_nextscn(elf
, scn
)) != NULL
) {
669 shdr
= gelf_getshdr(scn
, &shdr_mem
);
672 char *secname
= elf_strptr(elf
, strndx
, shdr
->sh_name
);
673 if (strcmp(secname
, ".SUNW_ctf") == 0) {
674 data
= elf_getdata(scn
, data
);
679 * OK, if we have the section, that is ok, we can just replace the
680 * data, if not, I made a mistake on the small amount of boilerplate
681 * below, probably .relA.ted to relocations...
684 /* Now we look if the ".SUNW_ctf" string is in the strings table */
685 scn
= elf_getscn(elf
, strndx
);
686 shdr
= gelf_getshdr(scn
, &shdr_mem
);
688 data
= elf_getdata(scn
, data
);
690 fprintf(stderr
, "Looking for the string\n");
691 size_t ctf_name_offset
= 1; /* First byte is '\0' */
692 while (ctf_name_offset
< data
->d_size
) {
693 const char *cur_str
= data
->d_buf
+ ctf_name_offset
;
695 fprintf(stderr
, "*-> %s\n", cur_str
);
696 if (strcmp(cur_str
, ".SUNW_ctf") == 0)
697 goto found_SUNW_ctf_str
;
699 ctf_name_offset
+= strlen(cur_str
) + 1;
702 /* Add the section name */
703 const size_t ctf_name_len
= strlen(".SUNW_ctf") + 1;
704 char *new_strings_table
= malloc(data
->d_size
+ ctf_name_len
);
705 if (new_strings_table
== NULL
)
708 memcpy(new_strings_table
, data
->d_buf
, data
->d_size
);
709 strcpy(new_strings_table
+ data
->d_size
, ".SUNW_ctf");
710 ctf_name_offset
= data
->d_size
;
711 data
->d_size
+= ctf_name_len
;
712 data
->d_buf
= new_strings_table
;
713 elf_flagdata(data
, ELF_C_SET
, ELF_F_DIRTY
);
714 elf_flagshdr(scn
, ELF_C_SET
, ELF_F_DIRTY
);
718 newscn
= elf_newscn(elf
);
722 data
= elf_newdata(newscn
);
726 shdr
= gelf_getshdr(newscn
, &shdr_mem
);
727 shdr
->sh_name
= ctf_name_offset
;
728 shdr
->sh_type
= SHT_PROGBITS
;
729 gelf_update_shdr(newscn
, &shdr_mem
);
730 elf_flagshdr(newscn
, ELF_C_SET
, ELF_F_DIRTY
);
732 char pathname
[PATH_MAX
];
733 snprintf(pathname
, sizeof(pathname
), "%s.SUNW_ctf", ctf
->filename
);
734 fd
= creat(pathname
, S_IRUSR
| S_IWUSR
);
736 fprintf(stderr
, "%s: open(%s) failed!\n", __func__
, pathname
);
739 if (write(fd
, bf
, size
) != size
)
745 char cmd
[PATH_MAX
* 2];
746 snprintf(cmd
, sizeof(cmd
), "objcopy --add-section .SUNW_ctf=%s %s",
747 pathname
, ctf
->filename
);
748 if (system(cmd
) == 0)
757 elf_flagdata(data
, ELF_C_SET
, ELF_F_DIRTY
);
759 if (elf_update(elf
, ELF_C_NULL
) < 0)
761 if (elf_update(elf
, ELF_C_WRITE
) < 0)