1 /* Textual dumping of CTF data.
2 Copyright (C) 2019-2021 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 char *cdm_toplevel_indent;
51 } ctf_dump_membstate_t;
54 ctf_dump_append (ctf_dump_state_t *state, char *str)
58 if ((cdi = malloc (sizeof (struct ctf_dump_item))) == NULL)
59 return (ctf_set_errno (state->cds_fp, ENOMEM));
62 ctf_list_append (&state->cds_items, cdi);
67 ctf_dump_free (ctf_dump_state_t *state)
69 ctf_dump_item_t *cdi, *next_cdi;
74 for (cdi = ctf_list_next (&state->cds_items); cdi != NULL;
78 next_cdi = ctf_list_next (cdi);
83 /* Return a dump for a single type, without member info: but do show the
87 ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
90 char *str = NULL, *bit = NULL, *buf = NULL;
97 int kind, unsliced_kind;
98 const char *nonroot_leader = "";
99 const char *nonroot_trailer = "";
102 if (flag == CTF_ADD_NONROOT)
104 nonroot_leader = "{";
105 nonroot_trailer = "}";
108 buf = ctf_type_aname (fp, id);
111 if (id == 0 || ctf_errno (fp) == ECTF_NONREPRESENTABLE)
113 str = str_append (str, " (type not represented in CTF)");
114 ctf_set_errno (fp, ECTF_NOTREF);
121 if (asprintf (&bit, " %s0x%lx: ", nonroot_leader, id) < 0)
123 str = str_append (str, bit);
128 str = str_append (str, buf);
132 unsliced_kind = ctf_type_kind_unsliced (fp, id);
133 kind = ctf_type_kind (fp, id);
135 /* Slices get a different print representation. */
136 if (unsliced_kind == CTF_K_SLICE)
138 ctf_type_encoding (fp, id, &enc);
139 if (asprintf (&bit, " [slice 0x%x:0x%x]",
140 enc.cte_offset, enc.cte_bits) < 0)
143 else if (kind == CTF_K_INTEGER)
145 ctf_type_encoding (fp, id, &enc);
146 if (asprintf (&bit, " [0x%x:0x%x]",
147 enc.cte_offset, enc.cte_bits) < 0)
150 str = str_append (str, bit);
154 if (kind != CTF_K_FUNCTION && kind != CTF_K_FORWARD)
155 if (asprintf (&bit, " (size 0x%lx)%s",
156 (unsigned long) ctf_type_size (fp, id),
157 nonroot_trailer) < 0)
160 str = str_append (str, bit);
164 /* Keep going as long as this type references another. We consider arrays
165 to "reference" their element type. */
167 if (kind == CTF_K_ARRAY)
169 if (ctf_array_info (fp, id, &ar) < 0)
171 new_id = ar.ctr_contents;
174 new_id = ctf_type_reference (fp, id);
175 if (new_id != CTF_ERR)
176 str = str_append (str, " ->");
177 } while (new_id != CTF_ERR);
179 if (ctf_errno (fp) != ECTF_NOTREF)
188 ctf_set_errno (fp, errno);
190 ctf_err_warn (fp, 1, 0, _("cannot format name dumping type 0x%lx"), id);
197 /* Dump one string field from the file header into the cds_items. */
199 ctf_dump_header_strfield (ctf_dict_t *fp, ctf_dump_state_t *state,
200 const char *name, uint32_t value)
205 if (asprintf (&str, "%s: %s\n", name, ctf_strptr (fp, value)) < 0)
207 ctf_dump_append (state, str);
212 return (ctf_set_errno (fp, errno));
215 /* Dump one section-offset field from the file header into the cds_items. */
217 ctf_dump_header_sectfield (ctf_dict_t *fp, ctf_dump_state_t *state,
218 const char *sect, uint32_t off, uint32_t nextoff)
223 if (asprintf (&str, "%s:\t0x%lx -- 0x%lx (0x%lx bytes)\n", sect,
224 (unsigned long) off, (unsigned long) (nextoff - 1),
225 (unsigned long) (nextoff - off)) < 0)
227 ctf_dump_append (state, str);
232 return (ctf_set_errno (fp, errno));
235 /* Dump the file header into the cds_items. */
237 ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
240 char *flagstr = NULL;
241 const ctf_header_t *hp = fp->ctf_header;
242 const char *vertab[] =
244 NULL, "CTF_VERSION_1",
245 "CTF_VERSION_1_UPGRADED_3 (latest format, version 1 type "
248 "CTF_VERSION_3", NULL
250 const char *verstr = NULL;
252 if (asprintf (&str, "Magic number: 0x%x\n", hp->cth_magic) < 0)
254 ctf_dump_append (state, str);
256 if (hp->cth_version <= CTF_VERSION)
257 verstr = vertab[hp->cth_version];
260 verstr = "(not a valid version)";
262 if (asprintf (&str, "Version: %i (%s)\n", hp->cth_version,
265 ctf_dump_append (state, str);
267 /* Everything else is only printed if present. */
269 /* The flags are unusual in that they represent the ctf_dict_t *in memory*:
270 flags representing compression, etc, are turned off as the file is
271 decompressed. So we store a copy of the flags before they are changed, for
274 if (fp->ctf_openflags > 0)
276 if (asprintf (&flagstr, "%s%s%s%s%s%s%s",
277 fp->ctf_openflags & CTF_F_COMPRESS
278 ? "CTF_F_COMPRESS": "",
279 (fp->ctf_openflags & CTF_F_COMPRESS)
280 && (fp->ctf_openflags & ~CTF_F_COMPRESS)
282 fp->ctf_openflags & CTF_F_NEWFUNCINFO
283 ? "CTF_F_NEWFUNCINFO" : "",
284 (fp->ctf_openflags & (CTF_F_COMPRESS | CTF_F_NEWFUNCINFO))
285 && (fp->ctf_openflags & ~(CTF_F_COMPRESS | CTF_F_NEWFUNCINFO))
287 fp->ctf_openflags & CTF_F_IDXSORTED
288 ? "CTF_F_IDXSORTED" : "",
289 fp->ctf_openflags & (CTF_F_COMPRESS | CTF_F_NEWFUNCINFO
291 && (fp->ctf_openflags & ~(CTF_F_COMPRESS | CTF_F_NEWFUNCINFO
294 fp->ctf_openflags & CTF_F_DYNSTR
295 ? "CTF_F_DYNSTR" : "") < 0)
298 if (asprintf (&str, "Flags: 0x%x (%s)", fp->ctf_openflags, flagstr) < 0)
300 ctf_dump_append (state, str);
303 if (ctf_dump_header_strfield (fp, state, "Parent label",
304 hp->cth_parlabel) < 0)
307 if (ctf_dump_header_strfield (fp, state, "Parent name", hp->cth_parname) < 0)
310 if (ctf_dump_header_strfield (fp, state, "Compilation unit name",
314 if (ctf_dump_header_sectfield (fp, state, "Label section", hp->cth_lbloff,
315 hp->cth_objtoff) < 0)
318 if (ctf_dump_header_sectfield (fp, state, "Data object section",
319 hp->cth_objtoff, hp->cth_funcoff) < 0)
322 if (ctf_dump_header_sectfield (fp, state, "Function info section",
323 hp->cth_funcoff, hp->cth_objtidxoff) < 0)
326 if (ctf_dump_header_sectfield (fp, state, "Object index section",
327 hp->cth_objtidxoff, hp->cth_funcidxoff) < 0)
330 if (ctf_dump_header_sectfield (fp, state, "Function index section",
331 hp->cth_funcidxoff, hp->cth_varoff) < 0)
334 if (ctf_dump_header_sectfield (fp, state, "Variable section",
335 hp->cth_varoff, hp->cth_typeoff) < 0)
338 if (ctf_dump_header_sectfield (fp, state, "Type section",
339 hp->cth_typeoff, hp->cth_stroff) < 0)
342 if (ctf_dump_header_sectfield (fp, state, "String section", hp->cth_stroff,
343 hp->cth_stroff + hp->cth_strlen + 1) < 0)
349 return (ctf_set_errno (fp, errno));
352 /* Dump a single label into the cds_items. */
355 ctf_dump_label (const char *name, const ctf_lblinfo_t *info,
360 ctf_dump_state_t *state = arg;
362 if (asprintf (&str, "%s -> ", name) < 0)
363 return (ctf_set_errno (state->cds_fp, errno));
365 if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type,
366 CTF_ADD_ROOT)) == NULL)
369 return 0; /* Swallow the error. */
372 str = str_append (str, typestr);
375 ctf_dump_append (state, str);
379 /* Dump all the object or function entries into the cds_items. */
382 ctf_dump_objts (ctf_dict_t *fp, ctf_dump_state_t *state, int functions)
386 ctf_next_t *i = NULL;
389 if ((functions && fp->ctf_funcidx_names)
390 || (!functions && fp->ctf_objtidx_names))
391 str = str_append (str, _("Section is indexed.\n"));
392 else if (fp->ctf_symtab.cts_data == NULL)
393 str = str_append (str, _("No symbol table.\n"));
395 while ((id = ctf_symbol_next (fp, &i, &name, functions)) != CTF_ERR)
397 char *typestr = NULL;
399 /* Emit the name, if we know it. No trailing space: ctf_dump_format_type
400 has a leading one. */
403 if (asprintf (&str, "%s ->", name) < 0)
409 if ((typestr = ctf_dump_format_type (state->cds_fp, id,
410 CTF_ADD_ROOT)) == NULL)
412 ctf_dump_append (state, str);
413 continue; /* Swallow the error. */
416 str = str_append (str, typestr);
418 ctf_dump_append (state, str);
422 ctf_set_errno (fp, ENOMEM);
423 ctf_next_destroy (i);
429 /* Dump a single variable into the cds_items. */
431 ctf_dump_var (const char *name, ctf_id_t type, void *arg)
435 ctf_dump_state_t *state = arg;
437 if (asprintf (&str, "%s -> ", name) < 0)
438 return (ctf_set_errno (state->cds_fp, errno));
440 if ((typestr = ctf_dump_format_type (state->cds_fp, type,
441 CTF_ADD_ROOT)) == NULL)
444 return 0; /* Swallow the error. */
447 str = str_append (str, typestr);
450 ctf_dump_append (state, str);
454 /* Report the number of digits in the hexadecimal representation of a type
458 type_hex_digits (ctf_id_t id)
465 for (; id > 0; id >>= 4, i++);
469 /* Dump a single member into the string in the membstate. */
471 ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
472 int depth, void *arg)
474 ctf_dump_membstate_t *state = arg;
475 char *typestr = NULL;
478 int has_encoding = 0;
479 int opened_paren = 0;
485 if (asprintf (&state->cdm_toplevel_indent, " %*s",
486 type_hex_digits (id), "") < 0)
490 if (asprintf (&bit, "%s%*s", state->cdm_toplevel_indent, depth * 4, "") < 0)
492 *state->cdm_str = str_append (*state->cdm_str, bit);
495 if ((typestr = ctf_type_aname (state->cdm_fp, id)) == NULL)
497 if (id == 0 || ctf_errno (state->cdm_fp) == ECTF_NONREPRESENTABLE)
499 if (asprintf (&bit, "[0x%lx] (type not represented in CTF)",
503 *state->cdm_str = str_append (*state->cdm_str, bit);
509 return -1; /* errno is set for us. */
512 if (ctf_type_encoding (state->cdm_fp, id, &ep) == 0)
515 ctf_type_encoding (state->cdm_fp, id, &ep);
517 if (asprintf (&bit, "[0x%lx] (ID 0x%lx) (kind %i) %s%s%s:%i "
518 "(aligned at 0x%lx", offset, id,
519 ctf_type_kind (state->cdm_fp, id), typestr,
520 (name[0] != 0 && typestr[0] != 0) ? " " : "", name,
521 ep.cte_bits, (unsigned long) ctf_type_align (state->cdm_fp,
526 else if (ctf_type_kind (state->cdm_fp, id) != CTF_K_FORWARD)
528 if (asprintf (&bit, "[0x%lx] (ID 0x%lx) (kind %i) %s%s%s "
529 "(aligned at 0x%lx", offset, id,
530 ctf_type_kind (state->cdm_fp, id), typestr,
531 (name[0] != 0 && typestr[0] != 0) ? " " : "", name,
532 (unsigned long) ctf_type_align (state->cdm_fp, id)) < 0)
536 else /* Forwards have no alignment. */
538 if (asprintf (&bit, "[0x%lx] (ID 0x%lx) (kind %i) %s%s%s\n", offset, id,
539 ctf_type_kind (state->cdm_fp, id), typestr,
540 (name[0] != 0 && typestr[0] != 0) ? " " : "", name) < 0)
544 *state->cdm_str = str_append (*state->cdm_str, bit);
552 if (asprintf (&bit, ", format 0x%x, offset:bits 0x%x:0x%x", ep.cte_format,
553 ep.cte_offset, ep.cte_bits) < 0)
555 *state->cdm_str = str_append (*state->cdm_str, bit);
561 *state->cdm_str = str_append (*state->cdm_str, ")\n");
567 return (ctf_set_errno (state->cdm_fp, errno));
570 /* Dump a single type into the cds_items. */
572 ctf_dump_type (ctf_id_t id, int flag, void *arg)
575 ctf_dump_state_t *state = arg;
576 ctf_dump_membstate_t membstate = { &str, state->cds_fp, NULL };
579 if ((str = ctf_dump_format_type (state->cds_fp, id, flag)) == NULL)
582 str = str_append (str, "\n");
583 if ((ctf_type_visit (state->cds_fp, id, ctf_dump_member, &membstate)) < 0)
585 if (id == 0 || ctf_errno (state->cds_fp) == ECTF_NONREPRESENTABLE)
587 ctf_dump_append (state, str);
590 ctf_err_warn (state->cds_fp, 1, ctf_errno (state->cds_fp),
591 _("cannot visit members dumping type 0x%lx"), id);
594 free (membstate.cdm_toplevel_indent);
596 /* Trim off the last linefeed added by ctf_dump_member(). */
598 if (str[len-1] == '\n')
601 ctf_dump_append (state, str);
605 free (membstate.cdm_toplevel_indent);
607 return 0; /* Swallow the error. */
610 /* Dump the string table into the cds_items. */
613 ctf_dump_str (ctf_dict_t *fp, ctf_dump_state_t *state)
615 const char *s = fp->ctf_str[CTF_STRTAB_0].cts_strs;
617 for (; s < fp->ctf_str[CTF_STRTAB_0].cts_strs +
618 fp->ctf_str[CTF_STRTAB_0].cts_len;)
621 if (asprintf (&str, "0x%lx: %s",
622 (unsigned long) (s - fp->ctf_str[CTF_STRTAB_0].cts_strs),
624 return (ctf_set_errno (fp, errno));
625 ctf_dump_append (state, str);
632 /* Dump a particular section of a CTF file, in textual form. Call with a
633 pointer to a NULL STATE: each call emits a dynamically allocated string
634 containing a description of one entity in the specified section, in order.
635 Only the first call (with a NULL state) may vary SECT. Once the CTF section
636 has been entirely dumped, the call returns NULL and frees and annuls the
637 STATE, ready for another section to be dumped. The returned textual content
638 may span multiple lines: between each call the FUNC is called with one
639 textual line at a time, and should return a suitably decorated line (it can
640 allocate a new one and return it if it likes). */
643 ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
644 ctf_dump_decorate_f *func, void *arg)
648 ctf_dump_state_t *state = NULL;
652 /* Data collection. Transforming a call-at-a-time iterator into a
653 return-at-a-time iterator in a language without call/cc is annoying. It
654 is easiest to simply collect everything at once and then return it bit
655 by bit. The first call will take (much) longer than otherwise, but the
656 amortized time needed is the same. */
658 if ((*statep = malloc (sizeof (struct ctf_dump_state))) == NULL)
660 ctf_set_errno (fp, ENOMEM);
665 memset (state, 0, sizeof (struct ctf_dump_state));
667 state->cds_sect = sect;
671 case CTF_SECT_HEADER:
672 ctf_dump_header (fp, state);
675 if (ctf_label_iter (fp, ctf_dump_label, state) < 0)
677 if (ctf_errno (fp) != ECTF_NOLABELDATA)
678 goto end; /* errno is set for us. */
679 ctf_set_errno (fp, 0);
683 if (ctf_dump_objts (fp, state, 0) < 0)
684 goto end; /* errno is set for us. */
687 if (ctf_dump_objts (fp, state, 1) < 0)
688 goto end; /* errno is set for us. */
691 if (ctf_variable_iter (fp, ctf_dump_var, state) < 0)
692 goto end; /* errno is set for us. */
695 if (ctf_type_iter_all (fp, ctf_dump_type, state) < 0)
696 goto end; /* errno is set for us. */
699 ctf_dump_str (fp, state);
702 ctf_set_errno (fp, ECTF_DUMPSECTUNKNOWN);
710 if (state->cds_sect != sect)
712 ctf_set_errno (fp, ECTF_DUMPSECTCHANGED);
717 if (state->cds_current == NULL)
718 state->cds_current = ctf_list_next (&state->cds_items);
720 state->cds_current = ctf_list_next (state->cds_current);
722 if (state->cds_current == NULL)
725 /* Hookery. There is some extra complexity to preserve linefeeds within each
726 item while removing linefeeds at the end. */
732 for (line = state->cds_current->cdi_item; line && *line; )
737 nline = strchr (line, '\n');
741 ret = func (sect, line, arg);
742 str = str_append (str, ret);
743 str = str_append (str, "\n");
758 if (str[len-1] == '\n')
763 str = strdup (state->cds_current->cdi_item);
766 ctf_set_errno (fp, ENOMEM);
771 ctf_set_errno (fp, 0);
775 ctf_dump_free (state);
777 ctf_set_errno (fp, 0);