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, "Cannot format name dumping type 0x%lx: %s", id
,
178 ctf_errmsg (ctf_errno (fp
)));
185 /* Dump one string field from the file header into the cds_items. */
187 ctf_dump_header_strfield (ctf_file_t
*fp
, ctf_dump_state_t
*state
,
188 const char *name
, uint32_t value
)
193 if (asprintf (&str
, "%s: %s\n", name
, ctf_strptr (fp
, value
)) < 0)
195 ctf_dump_append (state
, str
);
200 return (ctf_set_errno (fp
, errno
));
203 /* Dump one section-offset field from the file header into the cds_items. */
205 ctf_dump_header_sectfield (ctf_file_t
*fp
, ctf_dump_state_t
*state
,
206 const char *sect
, uint32_t off
, uint32_t nextoff
)
211 if (asprintf (&str
, "%s:\t0x%lx -- 0x%lx (0x%lx bytes)\n", sect
,
212 (unsigned long) off
, (unsigned long) (nextoff
- 1),
213 (unsigned long) (nextoff
- off
)) < 0)
215 ctf_dump_append (state
, str
);
220 return (ctf_set_errno (fp
, errno
));
223 /* Dump the file header into the cds_items. */
225 ctf_dump_header (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
228 const ctf_header_t
*hp
= fp
->ctf_header
;
229 const char *vertab
[] =
231 NULL
, "CTF_VERSION_1",
232 "CTF_VERSION_1_UPGRADED_3 (latest format, version 1 type "
235 "CTF_VERSION_3", NULL
237 const char *verstr
= NULL
;
239 if (asprintf (&str
, "Magic number: %x\n", hp
->cth_magic
) < 0)
241 ctf_dump_append (state
, str
);
243 if (hp
->cth_version
<= CTF_VERSION
)
244 verstr
= vertab
[hp
->cth_version
];
247 verstr
= "(not a valid version)";
249 if (asprintf (&str
, "Version: %i (%s)\n", hp
->cth_version
,
252 ctf_dump_append (state
, str
);
254 /* Everything else is only printed if present. */
256 /* The flags are unusual in that they represent the ctf_file_t *in memory*:
257 flags representing compression, etc, are turned off as the file is
258 decompressed. So we store a copy of the flags before they are changed, for
261 if (fp
->ctf_openflags
> 0)
263 if (fp
->ctf_openflags
)
264 if (asprintf (&str
, "Flags: 0x%x (%s)", fp
->ctf_openflags
,
265 fp
->ctf_openflags
& CTF_F_COMPRESS
? "CTF_F_COMPRESS"
268 ctf_dump_append (state
, str
);
271 if (ctf_dump_header_strfield (fp
, state
, "Parent label",
272 hp
->cth_parlabel
) < 0)
275 if (ctf_dump_header_strfield (fp
, state
, "Parent name", hp
->cth_parname
) < 0)
278 if (ctf_dump_header_strfield (fp
, state
, "Compilation unit name",
282 if (ctf_dump_header_sectfield (fp
, state
, "Label section", hp
->cth_lbloff
,
283 hp
->cth_objtoff
) < 0)
286 if (ctf_dump_header_sectfield (fp
, state
, "Data object section",
287 hp
->cth_objtoff
, hp
->cth_funcoff
) < 0)
290 if (ctf_dump_header_sectfield (fp
, state
, "Function info section",
291 hp
->cth_funcoff
, hp
->cth_varoff
) < 0)
294 if (ctf_dump_header_sectfield (fp
, state
, "Variable section",
295 hp
->cth_varoff
, hp
->cth_typeoff
) < 0)
298 if (ctf_dump_header_sectfield (fp
, state
, "Type section",
299 hp
->cth_typeoff
, hp
->cth_stroff
) < 0)
302 if (ctf_dump_header_sectfield (fp
, state
, "String section", hp
->cth_stroff
,
303 hp
->cth_stroff
+ hp
->cth_strlen
+ 1) < 0)
308 return (ctf_set_errno (fp
, errno
));
311 /* Dump a single label into the cds_items. */
314 ctf_dump_label (const char *name
, const ctf_lblinfo_t
*info
,
319 ctf_dump_state_t
*state
= arg
;
321 if (asprintf (&str
, "%s -> ", name
) < 0)
322 return (ctf_set_errno (state
->cds_fp
, errno
));
324 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, info
->ctb_type
,
325 CTF_ADD_ROOT
)) == NULL
)
328 return 0; /* Swallow the error. */
331 str
= str_append (str
, typestr
);
334 ctf_dump_append (state
, str
);
338 /* Dump all the object entries into the cds_items. (There is no iterator for
339 this section, so we just do it in a loop, and this function handles all of
340 them, rather than only one. */
343 ctf_dump_objts (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
347 for (i
= 0; i
< fp
->ctf_nsyms
; i
++)
351 const char *sym_name
;
354 if ((type
= ctf_lookup_by_symbol (state
->cds_fp
, i
)) == CTF_ERR
)
355 switch (ctf_errno (state
->cds_fp
))
357 /* Most errors are just an indication that this symbol is not a data
358 symbol, but this one indicates that we were called wrong, on a
359 CTF file with no associated symbol table. */
368 sym_name
= ctf_lookup_symbol_name (fp
, i
);
369 if (sym_name
[0] == '\0')
371 if (asprintf (&str
, "%lx -> ", (unsigned long) i
) < 0)
372 return (ctf_set_errno (fp
, errno
));
376 if (asprintf (&str
, "%s (%lx) -> ", sym_name
, (unsigned long) i
) < 0)
377 return (ctf_set_errno (fp
, errno
));
381 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, type
,
382 CTF_ADD_ROOT
)) == NULL
)
385 return 0; /* Swallow the error. */
388 str
= str_append (str
, typestr
);
391 ctf_dump_append (state
, str
);
396 /* Dump all the function entries into the cds_items. (As above, there is no
397 iterator for this section.) */
400 ctf_dump_funcs (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
404 for (i
= 0; i
< fp
->ctf_nsyms
; i
++)
409 const char *sym_name
;
413 if ((type
= ctf_func_info (state
->cds_fp
, i
, &fi
)) == CTF_ERR
)
414 switch (ctf_errno (state
->cds_fp
))
416 /* Most errors are just an indication that this symbol is not a data
417 symbol, but this one indicates that we were called wrong, on a
418 CTF file with no associated symbol table. */
427 /* Return type and all args. */
428 if ((bit
= ctf_type_aname (state
->cds_fp
, type
)) == NULL
)
430 err
= "look up return type";
434 /* Replace in the returned string, dropping in the function name. */
436 sym_name
= ctf_lookup_symbol_name (fp
, i
);
437 if (sym_name
[0] != '\0')
443 new_bit
= malloc (strlen (bit
) + 1 + strlen (sym_name
));
447 /* See ctf_type_aname. */
448 retstar
= strstr (bit
, "(*) (");
449 if (!ctf_assert (fp
, retstar
))
451 retstar
+= 2; /* After the '*' */
453 /* C is not good at search-and-replace. */
455 memcpy (walk
, bit
, retstar
- bit
);
456 walk
+= (retstar
- bit
);
457 strcpy (walk
, sym_name
);
458 walk
+= strlen (sym_name
);
459 strcpy (walk
, retstar
);
465 if (asprintf (&str
, "Symbol 0x%lx: %s", (unsigned long) i
, bit
) < 0)
469 ctf_dump_append (state
, str
);
473 ctf_err_warn (fp
, 1, "Cannot %s dumping function type for "
474 "symbol 0x%li: %s", err
, (unsigned long) i
,
475 ctf_errmsg (ctf_errno (state
->cds_fp
)));
477 return -1; /* errno is set for us. */
481 return (ctf_set_errno (fp
, errno
));
485 return -1; /* errno is set for us. */
490 /* Dump a single variable into the cds_items. */
492 ctf_dump_var (const char *name
, ctf_id_t type
, void *arg
)
496 ctf_dump_state_t
*state
= arg
;
498 if (asprintf (&str
, "%s -> ", name
) < 0)
499 return (ctf_set_errno (state
->cds_fp
, errno
));
501 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, type
,
502 CTF_ADD_ROOT
)) == NULL
)
505 return 0; /* Swallow the error. */
508 str
= str_append (str
, typestr
);
511 ctf_dump_append (state
, str
);
515 /* Dump a single member into the string in the membstate. */
517 ctf_dump_member (const char *name
, ctf_id_t id
, unsigned long offset
,
518 int depth
, void *arg
)
520 ctf_dump_membstate_t
*state
= arg
;
521 char *typestr
= NULL
;
524 int has_encoding
= 0;
527 for (i
= 0; i
< depth
; i
++)
528 *state
->cdm_str
= str_append (*state
->cdm_str
, " ");
530 if ((typestr
= ctf_type_aname (state
->cdm_fp
, id
)) == NULL
)
532 if (id
== 0 || ctf_errno (state
->cdm_fp
) == ECTF_NONREPRESENTABLE
)
534 if (asprintf (&bit
, " [0x%lx] (type not represented in CTF)",
538 *state
->cdm_str
= str_append (*state
->cdm_str
, bit
);
544 return -1; /* errno is set for us. */
547 if (ctf_type_encoding (state
->cdm_fp
, id
, &ep
) == 0)
550 ctf_type_encoding (state
->cdm_fp
, id
, &ep
);
552 if (asprintf (&bit
, " [0x%lx] (ID 0x%lx) (kind %i) %s%s%s:%i "
553 "(aligned at 0x%lx", offset
, id
,
554 ctf_type_kind (state
->cdm_fp
, id
), typestr
,
555 (name
[0] != 0 && typestr
[0] != 0) ? " " : "", name
,
556 ep
.cte_bits
, (unsigned long) ctf_type_align (state
->cdm_fp
,
562 if (asprintf (&bit
, " [0x%lx] (ID 0x%lx) (kind %i) %s%s%s "
563 "(aligned at 0x%lx", offset
, id
,
564 ctf_type_kind (state
->cdm_fp
, id
), typestr
,
565 (name
[0] != 0 && typestr
[0] != 0) ? " " : "", name
,
566 (unsigned long) ctf_type_align (state
->cdm_fp
, id
)) < 0)
570 *state
->cdm_str
= str_append (*state
->cdm_str
, bit
);
578 if (asprintf (&bit
, ", format 0x%x, offset:bits 0x%x:0x%x", ep
.cte_format
,
579 ep
.cte_offset
, ep
.cte_bits
) < 0)
581 *state
->cdm_str
= str_append (*state
->cdm_str
, bit
);
586 *state
->cdm_str
= str_append (*state
->cdm_str
, ")\n");
592 return (ctf_set_errno (state
->cdm_fp
, errno
));
595 /* Dump a single type into the cds_items. */
597 ctf_dump_type (ctf_id_t id
, int flag
, void *arg
)
601 ctf_dump_state_t
*state
= arg
;
602 ctf_dump_membstate_t membstate
= { &str
, state
->cds_fp
};
605 if ((str
= ctf_dump_format_type (state
->cds_fp
, id
, flag
)) == NULL
)
606 goto err_nomsg
; /* Error already logged for us. */
608 str
= str_append (str
, "\n");
609 if ((ctf_type_visit (state
->cds_fp
, id
, ctf_dump_member
, &membstate
)) < 0)
611 if (id
== 0 || ctf_errno (state
->cds_fp
) == ECTF_NONREPRESENTABLE
)
613 ctf_dump_append (state
, str
);
616 err
= "visit members";
620 /* Trim off the last linefeed added by ctf_dump_member(). */
622 if (str
[len
-1] == '\n')
625 ctf_dump_append (state
, str
);
629 ctf_err_warn (state
->cds_fp
, 1, "Cannot %s dumping type 0x%lx: %s",
630 err
, id
, ctf_errmsg (ctf_errno (state
->cds_fp
)));
633 return 0; /* Swallow the error. */
636 /* Dump the string table into the cds_items. */
639 ctf_dump_str (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
641 const char *s
= fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
;
643 for (; s
< fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
+
644 fp
->ctf_str
[CTF_STRTAB_0
].cts_len
;)
647 if (asprintf (&str
, "%lx: %s",
648 (unsigned long) (s
- fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
),
650 return (ctf_set_errno (fp
, errno
));
651 ctf_dump_append (state
, str
);
658 /* Dump a particular section of a CTF file, in textual form. Call with a
659 pointer to a NULL STATE: each call emits a dynamically allocated string
660 containing a description of one entity in the specified section, in order.
661 Only the first call (with a NULL state) may vary SECT. Once the CTF section
662 has been entirely dumped, the call returns NULL and frees and annuls the
663 STATE, ready for another section to be dumped. The returned textual content
664 may span multiple lines: between each call the FUNC is called with one
665 textual line at a time, and should return a suitably decorated line (it can
666 allocate a new one and return it if it likes). */
669 ctf_dump (ctf_file_t
*fp
, ctf_dump_state_t
**statep
, ctf_sect_names_t sect
,
670 ctf_dump_decorate_f
*func
, void *arg
)
674 ctf_dump_state_t
*state
= NULL
;
678 /* Data collection. Transforming a call-at-a-time iterator into a
679 return-at-a-time iterator in a language without call/cc is annoying. It
680 is easiest to simply collect everything at once and then return it bit
681 by bit. The first call will take (much) longer than otherwise, but the
682 amortized time needed is the same. */
684 if ((*statep
= malloc (sizeof (struct ctf_dump_state
))) == NULL
)
686 ctf_set_errno (fp
, ENOMEM
);
691 memset (state
, 0, sizeof (struct ctf_dump_state
));
693 state
->cds_sect
= sect
;
697 case CTF_SECT_HEADER
:
698 ctf_dump_header (fp
, state
);
701 if (ctf_label_iter (fp
, ctf_dump_label
, state
) < 0)
703 if (ctf_errno (fp
) != ECTF_NOLABELDATA
)
704 goto end
; /* errno is set for us. */
705 ctf_set_errno (fp
, 0);
709 if (ctf_dump_objts (fp
, state
) < 0)
710 goto end
; /* errno is set for us. */
713 if (ctf_dump_funcs (fp
, state
) < 0)
714 goto end
; /* errno is set for us. */
717 if (ctf_variable_iter (fp
, ctf_dump_var
, state
) < 0)
718 goto end
; /* errno is set for us. */
721 if (ctf_type_iter_all (fp
, ctf_dump_type
, state
) < 0)
722 goto end
; /* errno is set for us. */
725 ctf_dump_str (fp
, state
);
728 ctf_set_errno (fp
, ECTF_DUMPSECTUNKNOWN
);
736 if (state
->cds_sect
!= sect
)
738 ctf_set_errno (fp
, ECTF_DUMPSECTCHANGED
);
743 if (state
->cds_current
== NULL
)
744 state
->cds_current
= ctf_list_next (&state
->cds_items
);
746 state
->cds_current
= ctf_list_next (state
->cds_current
);
748 if (state
->cds_current
== NULL
)
751 /* Hookery. There is some extra complexity to preserve linefeeds within each
752 item while removing linefeeds at the end. */
758 for (line
= state
->cds_current
->cdi_item
; line
&& *line
; )
763 nline
= strchr (line
, '\n');
767 ret
= func (sect
, line
, arg
);
768 str
= str_append (str
, ret
);
769 str
= str_append (str
, "\n");
784 if (str
[len
-1] == '\n')
789 str
= strdup (state
->cds_current
->cdi_item
);
792 ctf_set_errno (fp
, ENOMEM
);
797 ctf_set_errno (fp
, 0);
801 ctf_dump_free (state
);
803 ctf_set_errno (fp
, 0);