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 const 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 optionally show
84 the type's references. */
86 #define CTF_FT_REFS 0x2 /* Print referenced types. */
87 #define CTF_FT_BITFIELD 0x4 /* Print :BITS if a bitfield. */
88 #define CTF_FT_ID 0x8 /* Print "ID: " in front of type IDs. */
91 ctf_dump_format_type (ctf_dict_t
*fp
, ctf_id_t id
, int flag
)
94 char *str
= NULL
, *bit
= NULL
, *buf
= NULL
;
96 ctf_set_errno (fp
, 0);
102 int kind
, unsliced_kind
;
103 const char *nonroot_leader
= "";
104 const char *nonroot_trailer
= "";
105 const char *idstr
= "";
108 if (flag
== CTF_ADD_NONROOT
)
110 nonroot_leader
= "{";
111 nonroot_trailer
= "}";
114 buf
= ctf_type_aname (fp
, id
);
117 if (id
== 0 || ctf_errno (fp
) == ECTF_NONREPRESENTABLE
)
119 ctf_set_errno (fp
, ECTF_NONREPRESENTABLE
);
120 str
= str_append (str
, " (type not represented in CTF)");
127 if (flag
& CTF_FT_ID
)
129 if (asprintf (&bit
, "%s%s0x%lx: (kind %i) ", nonroot_leader
, idstr
,
130 id
, ctf_type_kind (fp
, id
)) < 0)
132 str
= str_append (str
, bit
);
137 str
= str_append (str
, buf
);
142 unsliced_kind
= ctf_type_kind_unsliced (fp
, id
);
143 kind
= ctf_type_kind (fp
, id
);
145 if (ctf_type_encoding (fp
, id
, &ep
) == 0)
147 if (ep
.cte_bits
!= ctf_type_size (fp
, id
) * CHAR_BIT
148 && flag
& CTF_FT_BITFIELD
)
150 if (asprintf (&bit
, ":%i", ep
.cte_bits
) < 0)
152 str
= str_append (str
, bit
);
157 if (ep
.cte_bits
!= ctf_type_size (fp
, id
) * CHAR_BIT
158 || ep
.cte_offset
!= 0)
160 const char *slice
= "";
162 if (unsliced_kind
== CTF_K_SLICE
)
165 if (asprintf (&bit
, " [%s0x%x:0x%x]",
166 slice
, ep
.cte_offset
, ep
.cte_bits
) < 0)
168 str
= str_append (str
, bit
);
173 if (asprintf (&bit
, " (format 0x%x)", ep
.cte_format
) < 0)
175 str
= str_append (str
, bit
);
180 if (kind
!= CTF_K_FUNCTION
&& kind
!= CTF_K_FORWARD
)
182 if (asprintf (&bit
, " (size 0x%lx)",
183 (unsigned long) ctf_type_size (fp
, id
)) < 0)
186 str
= str_append (str
, bit
);
191 if (kind
!= CTF_K_FORWARD
)
193 if (asprintf (&bit
, " (aligned at 0x%lx)",
194 (unsigned long) ctf_type_align (fp
, id
)) < 0)
197 str
= str_append (str
, bit
);
202 if (nonroot_trailer
[0] != 0)
203 str
= str_append (str
, nonroot_trailer
);
205 /* Just exit after one iteration if we are not showing the types this type
207 if (!(flag
& CTF_FT_REFS
))
210 /* Keep going as long as this type references another. We consider arrays
211 to "reference" their element type. */
213 if (kind
== CTF_K_ARRAY
)
215 if (ctf_array_info (fp
, id
, &ar
) < 0)
217 new_id
= ar
.ctr_contents
;
220 new_id
= ctf_type_reference (fp
, id
);
221 if (new_id
!= CTF_ERR
)
222 str
= str_append (str
, " -> ");
223 } while (new_id
!= CTF_ERR
);
225 if (ctf_errno (fp
) != ECTF_NOTREF
)
234 ctf_set_errno (fp
, errno
);
236 ctf_err_warn (fp
, 1, 0, _("cannot format name dumping type 0x%lx"), id
);
243 /* Dump one string field from the file header into the cds_items. */
245 ctf_dump_header_strfield (ctf_dict_t
*fp
, ctf_dump_state_t
*state
,
246 const char *name
, uint32_t value
)
251 if (asprintf (&str
, "%s: %s\n", name
, ctf_strptr (fp
, value
)) < 0)
253 ctf_dump_append (state
, str
);
258 return (ctf_set_errno (fp
, errno
));
261 /* Dump one section-offset field from the file header into the cds_items. */
263 ctf_dump_header_sectfield (ctf_dict_t
*fp
, ctf_dump_state_t
*state
,
264 const char *sect
, uint32_t off
, uint32_t nextoff
)
269 if (asprintf (&str
, "%s:\t0x%lx -- 0x%lx (0x%lx bytes)\n", sect
,
270 (unsigned long) off
, (unsigned long) (nextoff
- 1),
271 (unsigned long) (nextoff
- off
)) < 0)
273 ctf_dump_append (state
, str
);
278 return (ctf_set_errno (fp
, errno
));
281 /* Dump the file header into the cds_items. */
283 ctf_dump_header (ctf_dict_t
*fp
, ctf_dump_state_t
*state
)
286 char *flagstr
= NULL
;
287 const ctf_header_t
*hp
= fp
->ctf_header
;
288 const char *vertab
[] =
290 NULL
, "CTF_VERSION_1",
291 "CTF_VERSION_1_UPGRADED_3 (latest format, version 1 type "
294 "CTF_VERSION_3", NULL
296 const char *verstr
= NULL
;
298 if (asprintf (&str
, "Magic number: 0x%x\n", hp
->cth_magic
) < 0)
300 ctf_dump_append (state
, str
);
302 if (hp
->cth_version
<= CTF_VERSION
)
303 verstr
= vertab
[hp
->cth_version
];
306 verstr
= "(not a valid version)";
308 if (asprintf (&str
, "Version: %i (%s)\n", hp
->cth_version
,
311 ctf_dump_append (state
, str
);
313 /* Everything else is only printed if present. */
315 /* The flags are unusual in that they represent the ctf_dict_t *in memory*:
316 flags representing compression, etc, are turned off as the file is
317 decompressed. So we store a copy of the flags before they are changed, for
320 if (fp
->ctf_openflags
> 0)
322 if (asprintf (&flagstr
, "%s%s%s%s%s%s%s",
323 fp
->ctf_openflags
& CTF_F_COMPRESS
324 ? "CTF_F_COMPRESS": "",
325 (fp
->ctf_openflags
& CTF_F_COMPRESS
)
326 && (fp
->ctf_openflags
& ~CTF_F_COMPRESS
)
328 fp
->ctf_openflags
& CTF_F_NEWFUNCINFO
329 ? "CTF_F_NEWFUNCINFO" : "",
330 (fp
->ctf_openflags
& (CTF_F_COMPRESS
| CTF_F_NEWFUNCINFO
))
331 && (fp
->ctf_openflags
& ~(CTF_F_COMPRESS
| CTF_F_NEWFUNCINFO
))
333 fp
->ctf_openflags
& CTF_F_IDXSORTED
334 ? "CTF_F_IDXSORTED" : "",
335 fp
->ctf_openflags
& (CTF_F_COMPRESS
| CTF_F_NEWFUNCINFO
337 && (fp
->ctf_openflags
& ~(CTF_F_COMPRESS
| CTF_F_NEWFUNCINFO
340 fp
->ctf_openflags
& CTF_F_DYNSTR
341 ? "CTF_F_DYNSTR" : "") < 0)
344 if (asprintf (&str
, "Flags: 0x%x (%s)", fp
->ctf_openflags
, flagstr
) < 0)
346 ctf_dump_append (state
, str
);
349 if (ctf_dump_header_strfield (fp
, state
, "Parent label",
350 hp
->cth_parlabel
) < 0)
353 if (ctf_dump_header_strfield (fp
, state
, "Parent name", hp
->cth_parname
) < 0)
356 if (ctf_dump_header_strfield (fp
, state
, "Compilation unit name",
360 if (ctf_dump_header_sectfield (fp
, state
, "Label section", hp
->cth_lbloff
,
361 hp
->cth_objtoff
) < 0)
364 if (ctf_dump_header_sectfield (fp
, state
, "Data object section",
365 hp
->cth_objtoff
, hp
->cth_funcoff
) < 0)
368 if (ctf_dump_header_sectfield (fp
, state
, "Function info section",
369 hp
->cth_funcoff
, hp
->cth_objtidxoff
) < 0)
372 if (ctf_dump_header_sectfield (fp
, state
, "Object index section",
373 hp
->cth_objtidxoff
, hp
->cth_funcidxoff
) < 0)
376 if (ctf_dump_header_sectfield (fp
, state
, "Function index section",
377 hp
->cth_funcidxoff
, hp
->cth_varoff
) < 0)
380 if (ctf_dump_header_sectfield (fp
, state
, "Variable section",
381 hp
->cth_varoff
, hp
->cth_typeoff
) < 0)
384 if (ctf_dump_header_sectfield (fp
, state
, "Type section",
385 hp
->cth_typeoff
, hp
->cth_stroff
) < 0)
388 if (ctf_dump_header_sectfield (fp
, state
, "String section", hp
->cth_stroff
,
389 hp
->cth_stroff
+ hp
->cth_strlen
+ 1) < 0)
395 return (ctf_set_errno (fp
, errno
));
398 /* Dump a single label into the cds_items. */
401 ctf_dump_label (const char *name
, const ctf_lblinfo_t
*info
,
406 ctf_dump_state_t
*state
= arg
;
408 if (asprintf (&str
, "%s -> ", name
) < 0)
409 return (ctf_set_errno (state
->cds_fp
, errno
));
411 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, info
->ctb_type
,
412 CTF_ADD_ROOT
| CTF_FT_REFS
)) == NULL
)
415 return 0; /* Swallow the error. */
418 str
= str_append (str
, typestr
);
421 ctf_dump_append (state
, str
);
425 /* Dump all the object or function entries into the cds_items. */
428 ctf_dump_objts (ctf_dict_t
*fp
, ctf_dump_state_t
*state
, int functions
)
432 ctf_next_t
*i
= NULL
;
435 if ((functions
&& fp
->ctf_funcidx_names
)
436 || (!functions
&& fp
->ctf_objtidx_names
))
437 str
= str_append (str
, _("Section is indexed.\n"));
438 else if (fp
->ctf_symtab
.cts_data
== NULL
)
439 str
= str_append (str
, _("No symbol table.\n"));
441 while ((id
= ctf_symbol_next (fp
, &i
, &name
, functions
)) != CTF_ERR
)
443 char *typestr
= NULL
;
445 /* Emit the name, if we know it. No trailing space: ctf_dump_format_type
446 has a leading one. */
449 if (asprintf (&str
, "%s -> ", name
) < 0)
455 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, id
,
456 CTF_ADD_ROOT
| CTF_FT_REFS
)) == NULL
)
458 ctf_dump_append (state
, str
);
459 continue; /* Swallow the error. */
462 str
= str_append (str
, typestr
);
464 ctf_dump_append (state
, str
);
468 ctf_set_errno (fp
, ENOMEM
);
469 ctf_next_destroy (i
);
475 /* Dump a single variable into the cds_items. */
477 ctf_dump_var (const char *name
, ctf_id_t type
, void *arg
)
481 ctf_dump_state_t
*state
= arg
;
483 if (asprintf (&str
, "%s -> ", name
) < 0)
484 return (ctf_set_errno (state
->cds_fp
, errno
));
486 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, type
,
487 CTF_ADD_ROOT
| CTF_FT_REFS
)) == NULL
)
490 return 0; /* Swallow the error. */
493 str
= str_append (str
, typestr
);
496 ctf_dump_append (state
, str
);
500 /* Dump a single struct/union member into the string in the membstate. */
502 ctf_dump_member (const char *name
, ctf_id_t id
, unsigned long offset
,
503 int depth
, void *arg
)
505 ctf_dump_membstate_t
*state
= arg
;
506 char *typestr
= NULL
;
509 /* The struct/union itself has already been printed. */
513 if (asprintf (&bit
, "%s%*s", state
->cdm_toplevel_indent
, (depth
-1)*4, "") < 0)
515 *state
->cdm_str
= str_append (*state
->cdm_str
, bit
);
518 if ((typestr
= ctf_dump_format_type (state
->cdm_fp
, id
,
519 CTF_ADD_ROOT
| CTF_FT_BITFIELD
520 | CTF_FT_ID
)) == NULL
)
521 return -1; /* errno is set for us. */
523 if (asprintf (&bit
, "[0x%lx] %s: %s\n", offset
, name
, typestr
) < 0)
526 *state
->cdm_str
= str_append (*state
->cdm_str
, bit
);
537 return (ctf_set_errno (state
->cdm_fp
, errno
));
540 /* Report the number of digits in the hexadecimal representation of a type
544 type_hex_digits (ctf_id_t id
)
551 for (; id
> 0; id
>>= 4, i
++);
555 /* Dump a single type into the cds_items. */
557 ctf_dump_type (ctf_id_t id
, int flag
, void *arg
)
562 ctf_dump_state_t
*state
= arg
;
563 ctf_dump_membstate_t membstate
= { &str
, state
->cds_fp
, NULL
};
566 if (asprintf (&indent
, " %*s", type_hex_digits (id
), "") < 0)
567 return (ctf_set_errno (state
->cds_fp
, ENOMEM
));
569 /* Dump the type itself. */
570 if ((str
= ctf_dump_format_type (state
->cds_fp
, id
,
571 flag
| CTF_FT_REFS
)) == NULL
)
573 str
= str_append (str
, "\n");
575 membstate
.cdm_toplevel_indent
= indent
;
577 /* Member dumping for structs, unions... */
578 if (ctf_type_kind (state
->cds_fp
, id
) == CTF_K_STRUCT
579 || ctf_type_kind (state
->cds_fp
, id
) == CTF_K_UNION
)
581 if ((ctf_type_visit (state
->cds_fp
, id
, ctf_dump_member
, &membstate
)) < 0)
583 if (id
== 0 || ctf_errno (state
->cds_fp
) == ECTF_NONREPRESENTABLE
)
585 ctf_dump_append (state
, str
);
588 ctf_err_warn (state
->cds_fp
, 1, ctf_errno (state
->cds_fp
),
589 _("cannot visit members dumping type 0x%lx"), id
);
594 /* ... and enums, for which we dump the first and last few members and skip
595 the ones in the middle. */
596 if (ctf_type_kind (state
->cds_fp
, id
) == CTF_K_ENUM
)
598 int enum_count
= ctf_member_count (state
->cds_fp
, id
);
599 ctf_next_t
*it
= NULL
;
601 const char *enumerand
;
605 while ((enumerand
= ctf_enum_next (state
->cds_fp
, id
,
606 &it
, &value
)) != NULL
)
609 if ((i
> 5) && (i
< enum_count
- 4))
612 str
= str_append (str
, indent
);
614 if (asprintf (&bit
, "%s: %i\n", enumerand
, value
) < 0)
617 ctf_next_destroy (it
);
620 str
= str_append (str
, bit
);
623 if ((i
== 5) && (enum_count
> 10))
625 str
= str_append (str
, indent
);
626 str
= str_append (str
, "...\n");
629 if (ctf_errno (state
->cds_fp
) != ECTF_NEXT_END
)
631 ctf_err_warn (state
->cds_fp
, 1, ctf_errno (state
->cds_fp
),
632 _("cannot visit enumerands dumping type 0x%lx"), id
);
637 ctf_dump_append (state
, str
);
645 return ctf_set_errno (state
->cds_fp
, err
);
648 /* Dump the string table into the cds_items. */
651 ctf_dump_str (ctf_dict_t
*fp
, ctf_dump_state_t
*state
)
653 const char *s
= fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
;
655 for (; s
< fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
+
656 fp
->ctf_str
[CTF_STRTAB_0
].cts_len
;)
659 if (asprintf (&str
, "0x%lx: %s",
660 (unsigned long) (s
- fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
),
662 return (ctf_set_errno (fp
, errno
));
663 ctf_dump_append (state
, str
);
670 /* Dump a particular section of a CTF file, in textual form. Call with a
671 pointer to a NULL STATE: each call emits a dynamically allocated string
672 containing a description of one entity in the specified section, in order.
673 Only the first call (with a NULL state) may vary SECT. Once the CTF section
674 has been entirely dumped, the call returns NULL and frees and annuls the
675 STATE, ready for another section to be dumped. The returned textual content
676 may span multiple lines: between each call the FUNC is called with one
677 textual line at a time, and should return a suitably decorated line (it can
678 allocate a new one and return it if it likes). */
681 ctf_dump (ctf_dict_t
*fp
, ctf_dump_state_t
**statep
, ctf_sect_names_t sect
,
682 ctf_dump_decorate_f
*func
, void *arg
)
686 ctf_dump_state_t
*state
= NULL
;
690 /* Data collection. Transforming a call-at-a-time iterator into a
691 return-at-a-time iterator in a language without call/cc is annoying. It
692 is easiest to simply collect everything at once and then return it bit
693 by bit. The first call will take (much) longer than otherwise, but the
694 amortized time needed is the same. */
696 if ((*statep
= malloc (sizeof (struct ctf_dump_state
))) == NULL
)
698 ctf_set_errno (fp
, ENOMEM
);
703 memset (state
, 0, sizeof (struct ctf_dump_state
));
705 state
->cds_sect
= sect
;
709 case CTF_SECT_HEADER
:
710 ctf_dump_header (fp
, state
);
713 if (ctf_label_iter (fp
, ctf_dump_label
, state
) < 0)
715 if (ctf_errno (fp
) != ECTF_NOLABELDATA
)
716 goto end
; /* errno is set for us. */
717 ctf_set_errno (fp
, 0);
721 if (ctf_dump_objts (fp
, state
, 0) < 0)
722 goto end
; /* errno is set for us. */
725 if (ctf_dump_objts (fp
, state
, 1) < 0)
726 goto end
; /* errno is set for us. */
729 if (ctf_variable_iter (fp
, ctf_dump_var
, state
) < 0)
730 goto end
; /* errno is set for us. */
733 if (ctf_type_iter_all (fp
, ctf_dump_type
, state
) < 0)
734 goto end
; /* errno is set for us. */
737 ctf_dump_str (fp
, state
);
740 ctf_set_errno (fp
, ECTF_DUMPSECTUNKNOWN
);
748 if (state
->cds_sect
!= sect
)
750 ctf_set_errno (fp
, ECTF_DUMPSECTCHANGED
);
755 if (state
->cds_current
== NULL
)
756 state
->cds_current
= ctf_list_next (&state
->cds_items
);
758 state
->cds_current
= ctf_list_next (state
->cds_current
);
760 if (state
->cds_current
== NULL
)
763 /* Hookery. There is some extra complexity to preserve linefeeds within each
764 item while removing linefeeds at the end. */
770 for (line
= state
->cds_current
->cdi_item
; line
&& *line
; )
775 nline
= strchr (line
, '\n');
779 ret
= func (sect
, line
, arg
);
780 str
= str_append (str
, ret
);
781 str
= str_append (str
, "\n");
796 if (str
[len
-1] == '\n')
801 str
= strdup (state
->cds_current
->cdi_item
);
804 ctf_set_errno (fp
, ENOMEM
);
809 ctf_set_errno (fp
, 0);
813 ctf_dump_free (state
);
815 ctf_set_errno (fp
, 0);