1 /* Textual dumping of CTF data.
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/>. */
23 #define str_append(s, a) ctf_str_append_noerr (s, a)
25 /* One item to be dumped, in string form. */
27 typedef struct ctf_dump_item
33 /* Cross-call state for dumping. Basically just enough to track the section in
34 use and a list of return strings. */
38 ctf_sect_names_t cds_sect
;
40 ctf_dump_item_t
*cds_current
;
44 /* Cross-call state for ctf_dump_member. */
46 typedef struct ctf_dump_membstate
50 } ctf_dump_membstate_t
;
53 ctf_dump_append (ctf_dump_state_t
*state
, char *str
)
57 if ((cdi
= malloc (sizeof (struct ctf_dump_item
))) == NULL
)
58 return (ctf_set_errno (state
->cds_fp
, ENOMEM
));
61 ctf_list_append (&state
->cds_items
, cdi
);
66 ctf_dump_free (ctf_dump_state_t
*state
)
68 ctf_dump_item_t
*cdi
, *next_cdi
;
73 for (cdi
= ctf_list_next (&state
->cds_items
); cdi
!= NULL
;
77 next_cdi
= ctf_list_next (cdi
);
82 /* Return a dump for a single type, without member info: but do show the
86 ctf_dump_format_type (ctf_file_t
*fp
, ctf_id_t id
, int flag
)
89 char *str
= NULL
, *bit
= NULL
, *buf
= NULL
;
95 const char *nonroot_leader
= "";
96 const char *nonroot_trailer
= "";
99 if (flag
== CTF_ADD_NONROOT
)
101 nonroot_leader
= "{";
102 nonroot_trailer
= "}";
105 buf
= ctf_type_aname (fp
, id
);
108 if (id
== 0 || ctf_errno (fp
) == ECTF_NONREPRESENTABLE
)
110 str
= str_append (str
, " (type not represented in CTF)");
111 ctf_set_errno (fp
, ECTF_NOTREF
);
118 if (asprintf (&bit
, " %s%lx: ", nonroot_leader
, id
) < 0)
120 str
= str_append (str
, bit
);
126 str
= str_append (str
, buf
);
127 str
= str_append (str
, " ");
133 /* Slices get a different print representation. */
134 if (ctf_type_kind_unsliced (fp
, id
) == CTF_K_SLICE
)
136 ctf_type_encoding (fp
, id
, &enc
);
137 if (asprintf (&bit
, "[slice 0x%x:0x%x] ",
138 enc
.cte_offset
, enc
.cte_bits
) < 0)
141 else if (ctf_type_kind (fp
, id
) == CTF_K_INTEGER
)
143 ctf_type_encoding (fp
, id
, &enc
);
144 if (asprintf (&bit
, "[0x%x:0x%x] ",
145 enc
.cte_offset
, enc
.cte_bits
) < 0)
148 str
= str_append (str
, bit
);
152 if (asprintf (&bit
, "(size 0x%lx)%s",
153 (unsigned long) ctf_type_size (fp
, id
),
154 nonroot_trailer
) < 0)
157 str
= str_append (str
, bit
);
161 new_id
= ctf_type_reference (fp
, id
);
162 if (new_id
!= CTF_ERR
)
163 str
= str_append (str
, " ->");
164 } while (new_id
!= CTF_ERR
);
166 if (ctf_errno (fp
) != ECTF_NOTREF
)
175 ctf_set_errno (fp
, errno
);
177 ctf_err_warn (fp
, 1, 0, _("cannot format name dumping type 0x%lx"), id
);
184 /* Dump one string field from the file header into the cds_items. */
186 ctf_dump_header_strfield (ctf_file_t
*fp
, ctf_dump_state_t
*state
,
187 const char *name
, uint32_t value
)
192 if (asprintf (&str
, "%s: %s\n", name
, ctf_strptr (fp
, value
)) < 0)
194 ctf_dump_append (state
, str
);
199 return (ctf_set_errno (fp
, errno
));
202 /* Dump one section-offset field from the file header into the cds_items. */
204 ctf_dump_header_sectfield (ctf_file_t
*fp
, ctf_dump_state_t
*state
,
205 const char *sect
, uint32_t off
, uint32_t nextoff
)
210 if (asprintf (&str
, "%s:\t0x%lx -- 0x%lx (0x%lx bytes)\n", sect
,
211 (unsigned long) off
, (unsigned long) (nextoff
- 1),
212 (unsigned long) (nextoff
- off
)) < 0)
214 ctf_dump_append (state
, str
);
219 return (ctf_set_errno (fp
, errno
));
222 /* Dump the file header into the cds_items. */
224 ctf_dump_header (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
227 const ctf_header_t
*hp
= fp
->ctf_header
;
228 const char *vertab
[] =
230 NULL
, "CTF_VERSION_1",
231 "CTF_VERSION_1_UPGRADED_3 (latest format, version 1 type "
234 "CTF_VERSION_3", NULL
236 const char *verstr
= NULL
;
238 if (asprintf (&str
, "Magic number: %x\n", hp
->cth_magic
) < 0)
240 ctf_dump_append (state
, str
);
242 if (hp
->cth_version
<= CTF_VERSION
)
243 verstr
= vertab
[hp
->cth_version
];
246 verstr
= "(not a valid version)";
248 if (asprintf (&str
, "Version: %i (%s)\n", hp
->cth_version
,
251 ctf_dump_append (state
, str
);
253 /* Everything else is only printed if present. */
255 /* The flags are unusual in that they represent the ctf_file_t *in memory*:
256 flags representing compression, etc, are turned off as the file is
257 decompressed. So we store a copy of the flags before they are changed, for
260 if (fp
->ctf_openflags
> 0)
262 if (fp
->ctf_openflags
)
263 if (asprintf (&str
, "Flags: 0x%x (%s)", fp
->ctf_openflags
,
264 fp
->ctf_openflags
& CTF_F_COMPRESS
? "CTF_F_COMPRESS"
267 ctf_dump_append (state
, str
);
270 if (ctf_dump_header_strfield (fp
, state
, "Parent label",
271 hp
->cth_parlabel
) < 0)
274 if (ctf_dump_header_strfield (fp
, state
, "Parent name", hp
->cth_parname
) < 0)
277 if (ctf_dump_header_strfield (fp
, state
, "Compilation unit name",
281 if (ctf_dump_header_sectfield (fp
, state
, "Label section", hp
->cth_lbloff
,
282 hp
->cth_objtoff
) < 0)
285 if (ctf_dump_header_sectfield (fp
, state
, "Data object section",
286 hp
->cth_objtoff
, hp
->cth_funcoff
) < 0)
289 if (ctf_dump_header_sectfield (fp
, state
, "Function info section",
290 hp
->cth_funcoff
, hp
->cth_varoff
) < 0)
293 if (ctf_dump_header_sectfield (fp
, state
, "Variable section",
294 hp
->cth_varoff
, hp
->cth_typeoff
) < 0)
297 if (ctf_dump_header_sectfield (fp
, state
, "Type section",
298 hp
->cth_typeoff
, hp
->cth_stroff
) < 0)
301 if (ctf_dump_header_sectfield (fp
, state
, "String section", hp
->cth_stroff
,
302 hp
->cth_stroff
+ hp
->cth_strlen
+ 1) < 0)
307 return (ctf_set_errno (fp
, errno
));
310 /* Dump a single label into the cds_items. */
313 ctf_dump_label (const char *name
, const ctf_lblinfo_t
*info
,
318 ctf_dump_state_t
*state
= arg
;
320 if (asprintf (&str
, "%s -> ", name
) < 0)
321 return (ctf_set_errno (state
->cds_fp
, errno
));
323 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, info
->ctb_type
,
324 CTF_ADD_ROOT
)) == NULL
)
327 return 0; /* Swallow the error. */
330 str
= str_append (str
, typestr
);
333 ctf_dump_append (state
, str
);
337 /* Dump all the object entries into the cds_items. (There is no iterator for
338 this section, so we just do it in a loop, and this function handles all of
339 them, rather than only one. */
342 ctf_dump_objts (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
346 for (i
= 0; i
< fp
->ctf_nsyms
; i
++)
350 const char *sym_name
;
353 if ((type
= ctf_lookup_by_symbol (state
->cds_fp
, i
)) == CTF_ERR
)
354 switch (ctf_errno (state
->cds_fp
))
356 /* Most errors are just an indication that this symbol is not a data
357 symbol, but this one indicates that we were called wrong, on a
358 CTF file with no associated symbol table. */
367 sym_name
= ctf_lookup_symbol_name (fp
, i
);
368 if (sym_name
[0] == '\0')
370 if (asprintf (&str
, "%lx -> ", (unsigned long) i
) < 0)
371 return (ctf_set_errno (fp
, errno
));
375 if (asprintf (&str
, "%s (%lx) -> ", sym_name
, (unsigned long) i
) < 0)
376 return (ctf_set_errno (fp
, errno
));
380 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, type
,
381 CTF_ADD_ROOT
)) == NULL
)
384 return 0; /* Swallow the error. */
387 str
= str_append (str
, typestr
);
390 ctf_dump_append (state
, str
);
395 /* Dump all the function entries into the cds_items. (As above, there is no
396 iterator for this section.) */
399 ctf_dump_funcs (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
403 for (i
= 0; i
< fp
->ctf_nsyms
; i
++)
407 const char *sym_name
;
411 if ((type
= ctf_func_info (state
->cds_fp
, i
, &fi
)) == CTF_ERR
)
412 switch (ctf_errno (state
->cds_fp
))
414 /* Most errors are just an indication that this symbol is not a data
415 symbol, but this one indicates that we were called wrong, on a
416 CTF file with no associated symbol table. */
425 /* Return type and all args. */
426 if ((bit
= ctf_type_aname (state
->cds_fp
, type
)) == NULL
)
428 ctf_err_warn (fp
, 1, ctf_errno (state
->cds_fp
),
429 _("cannot look up return type dumping function type "
430 "for symbol 0x%li"), (unsigned long) i
);
432 return -1; /* errno is set for us. */
435 /* Replace in the returned string, dropping in the function name. */
437 sym_name
= ctf_lookup_symbol_name (fp
, i
);
438 if (sym_name
[0] != '\0')
444 new_bit
= malloc (strlen (bit
) + 1 + strlen (sym_name
));
448 /* See ctf_type_aname. */
449 retstar
= strstr (bit
, "(*) (");
450 if (!ctf_assert (fp
, retstar
))
452 retstar
+= 2; /* After the '*' */
454 /* C is not good at search-and-replace. */
456 memcpy (walk
, bit
, retstar
- bit
);
457 walk
+= (retstar
- bit
);
458 strcpy (walk
, sym_name
);
459 walk
+= strlen (sym_name
);
460 strcpy (walk
, retstar
);
466 if (asprintf (&str
, "Symbol 0x%lx: %s", (unsigned long) i
, bit
) < 0)
470 ctf_dump_append (state
, str
);
475 return (ctf_set_errno (fp
, errno
));
479 return -1; /* errno is set for us. */
484 /* Dump a single variable into the cds_items. */
486 ctf_dump_var (const char *name
, ctf_id_t type
, void *arg
)
490 ctf_dump_state_t
*state
= arg
;
492 if (asprintf (&str
, "%s -> ", name
) < 0)
493 return (ctf_set_errno (state
->cds_fp
, errno
));
495 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, type
,
496 CTF_ADD_ROOT
)) == NULL
)
499 return 0; /* Swallow the error. */
502 str
= str_append (str
, typestr
);
505 ctf_dump_append (state
, str
);
509 /* Dump a single member into the string in the membstate. */
511 ctf_dump_member (const char *name
, ctf_id_t id
, unsigned long offset
,
512 int depth
, void *arg
)
514 ctf_dump_membstate_t
*state
= arg
;
515 char *typestr
= NULL
;
518 int has_encoding
= 0;
521 for (i
= 0; i
< depth
; i
++)
522 *state
->cdm_str
= str_append (*state
->cdm_str
, " ");
524 if ((typestr
= ctf_type_aname (state
->cdm_fp
, id
)) == NULL
)
526 if (id
== 0 || ctf_errno (state
->cdm_fp
) == ECTF_NONREPRESENTABLE
)
528 if (asprintf (&bit
, " [0x%lx] (type not represented in CTF)",
532 *state
->cdm_str
= str_append (*state
->cdm_str
, bit
);
538 return -1; /* errno is set for us. */
541 if (ctf_type_encoding (state
->cdm_fp
, id
, &ep
) == 0)
544 ctf_type_encoding (state
->cdm_fp
, id
, &ep
);
546 if (asprintf (&bit
, " [0x%lx] (ID 0x%lx) (kind %i) %s%s%s:%i "
547 "(aligned at 0x%lx", offset
, id
,
548 ctf_type_kind (state
->cdm_fp
, id
), typestr
,
549 (name
[0] != 0 && typestr
[0] != 0) ? " " : "", name
,
550 ep
.cte_bits
, (unsigned long) ctf_type_align (state
->cdm_fp
,
556 if (asprintf (&bit
, " [0x%lx] (ID 0x%lx) (kind %i) %s%s%s "
557 "(aligned at 0x%lx", offset
, id
,
558 ctf_type_kind (state
->cdm_fp
, id
), typestr
,
559 (name
[0] != 0 && typestr
[0] != 0) ? " " : "", name
,
560 (unsigned long) ctf_type_align (state
->cdm_fp
, id
)) < 0)
564 *state
->cdm_str
= str_append (*state
->cdm_str
, bit
);
572 if (asprintf (&bit
, ", format 0x%x, offset:bits 0x%x:0x%x", ep
.cte_format
,
573 ep
.cte_offset
, ep
.cte_bits
) < 0)
575 *state
->cdm_str
= str_append (*state
->cdm_str
, bit
);
580 *state
->cdm_str
= str_append (*state
->cdm_str
, ")\n");
586 return (ctf_set_errno (state
->cdm_fp
, errno
));
589 /* Dump a single type into the cds_items. */
591 ctf_dump_type (ctf_id_t id
, int flag
, void *arg
)
594 ctf_dump_state_t
*state
= arg
;
595 ctf_dump_membstate_t membstate
= { &str
, state
->cds_fp
};
598 if ((str
= ctf_dump_format_type (state
->cds_fp
, id
, flag
)) == NULL
)
601 str
= str_append (str
, "\n");
602 if ((ctf_type_visit (state
->cds_fp
, id
, ctf_dump_member
, &membstate
)) < 0)
604 if (id
== 0 || ctf_errno (state
->cds_fp
) == ECTF_NONREPRESENTABLE
)
606 ctf_dump_append (state
, str
);
609 ctf_err_warn (state
->cds_fp
, 1, ctf_errno (state
->cds_fp
),
610 _("cannot visit members dumping type 0x%lx"), id
);
614 /* Trim off the last linefeed added by ctf_dump_member(). */
616 if (str
[len
-1] == '\n')
619 ctf_dump_append (state
, str
);
624 return 0; /* Swallow the error. */
627 /* Dump the string table into the cds_items. */
630 ctf_dump_str (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
632 const char *s
= fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
;
634 for (; s
< fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
+
635 fp
->ctf_str
[CTF_STRTAB_0
].cts_len
;)
638 if (asprintf (&str
, "%lx: %s",
639 (unsigned long) (s
- fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
),
641 return (ctf_set_errno (fp
, errno
));
642 ctf_dump_append (state
, str
);
649 /* Dump a particular section of a CTF file, in textual form. Call with a
650 pointer to a NULL STATE: each call emits a dynamically allocated string
651 containing a description of one entity in the specified section, in order.
652 Only the first call (with a NULL state) may vary SECT. Once the CTF section
653 has been entirely dumped, the call returns NULL and frees and annuls the
654 STATE, ready for another section to be dumped. The returned textual content
655 may span multiple lines: between each call the FUNC is called with one
656 textual line at a time, and should return a suitably decorated line (it can
657 allocate a new one and return it if it likes). */
660 ctf_dump (ctf_file_t
*fp
, ctf_dump_state_t
**statep
, ctf_sect_names_t sect
,
661 ctf_dump_decorate_f
*func
, void *arg
)
665 ctf_dump_state_t
*state
= NULL
;
669 /* Data collection. Transforming a call-at-a-time iterator into a
670 return-at-a-time iterator in a language without call/cc is annoying. It
671 is easiest to simply collect everything at once and then return it bit
672 by bit. The first call will take (much) longer than otherwise, but the
673 amortized time needed is the same. */
675 if ((*statep
= malloc (sizeof (struct ctf_dump_state
))) == NULL
)
677 ctf_set_errno (fp
, ENOMEM
);
682 memset (state
, 0, sizeof (struct ctf_dump_state
));
684 state
->cds_sect
= sect
;
688 case CTF_SECT_HEADER
:
689 ctf_dump_header (fp
, state
);
692 if (ctf_label_iter (fp
, ctf_dump_label
, state
) < 0)
694 if (ctf_errno (fp
) != ECTF_NOLABELDATA
)
695 goto end
; /* errno is set for us. */
696 ctf_set_errno (fp
, 0);
700 if (ctf_dump_objts (fp
, state
) < 0)
701 goto end
; /* errno is set for us. */
704 if (ctf_dump_funcs (fp
, state
) < 0)
705 goto end
; /* errno is set for us. */
708 if (ctf_variable_iter (fp
, ctf_dump_var
, state
) < 0)
709 goto end
; /* errno is set for us. */
712 if (ctf_type_iter_all (fp
, ctf_dump_type
, state
) < 0)
713 goto end
; /* errno is set for us. */
716 ctf_dump_str (fp
, state
);
719 ctf_set_errno (fp
, ECTF_DUMPSECTUNKNOWN
);
727 if (state
->cds_sect
!= sect
)
729 ctf_set_errno (fp
, ECTF_DUMPSECTCHANGED
);
734 if (state
->cds_current
== NULL
)
735 state
->cds_current
= ctf_list_next (&state
->cds_items
);
737 state
->cds_current
= ctf_list_next (state
->cds_current
);
739 if (state
->cds_current
== NULL
)
742 /* Hookery. There is some extra complexity to preserve linefeeds within each
743 item while removing linefeeds at the end. */
749 for (line
= state
->cds_current
->cdi_item
; line
&& *line
; )
754 nline
= strchr (line
, '\n');
758 ret
= func (sect
, line
, arg
);
759 str
= str_append (str
, ret
);
760 str
= str_append (str
, "\n");
775 if (str
[len
-1] == '\n')
780 str
= strdup (state
->cds_current
->cdi_item
);
783 ctf_set_errno (fp
, ENOMEM
);
788 ctf_set_errno (fp
, 0);
792 ctf_dump_free (state
);
794 ctf_set_errno (fp
, 0);