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 /* Slices need special handling to distinguish them from their referenced
86 ctf_is_slice (ctf_file_t
*fp
, ctf_id_t id
, ctf_encoding_t
*enc
)
88 int kind
= ctf_type_kind (fp
, id
);
90 return (((kind
== CTF_K_INTEGER
) || (kind
== CTF_K_ENUM
)
91 || (kind
== CTF_K_FLOAT
))
92 && ctf_type_reference (fp
, id
) != CTF_ERR
93 && ctf_type_encoding (fp
, id
, enc
) == 0);
96 /* Return a dump for a single type, without member info: but do show the
100 ctf_dump_format_type (ctf_file_t
*fp
, ctf_id_t id
, int flag
)
103 char *str
= NULL
, *bit
= NULL
, *buf
= NULL
;
109 const char *nonroot_leader
= "";
110 const char *nonroot_trailer
= "";
113 if (flag
== CTF_ADD_NONROOT
)
115 nonroot_leader
= "{";
116 nonroot_trailer
= "}";
119 buf
= ctf_type_aname (fp
, id
);
122 if (id
== 0 || ctf_errno (fp
) == ECTF_NONREPRESENTABLE
)
124 str
= str_append (str
, " (type not represented in CTF)");
125 ctf_set_errno (fp
, ECTF_NOTREF
);
132 /* Slices get a different print representation. */
134 if (ctf_is_slice (fp
, id
, &enc
))
136 ctf_type_encoding (fp
, id
, &enc
);
137 if (asprintf (&bit
, " %s%lx: [slice 0x%x:0x%x]%s",
138 nonroot_leader
, id
, enc
.cte_offset
, enc
.cte_bits
,
139 nonroot_trailer
) < 0)
144 if (asprintf (&bit
, " %s%lx: %s (size 0x%lx)%s", nonroot_leader
,
145 id
, buf
[0] == '\0' ? "(nameless)" : buf
,
146 (unsigned long) ctf_type_size (fp
, id
),
147 nonroot_trailer
) < 0)
152 str
= str_append (str
, bit
);
156 new_id
= ctf_type_reference (fp
, id
);
157 if (new_id
!= CTF_ERR
)
158 str
= str_append (str
, " ->");
159 } while (new_id
!= CTF_ERR
);
161 if (ctf_errno (fp
) != ECTF_NOTREF
)
170 ctf_set_errno (fp
, errno
);
178 /* Dump one string field from the file header into the cds_items. */
180 ctf_dump_header_strfield (ctf_file_t
*fp
, ctf_dump_state_t
*state
,
181 const char *name
, uint32_t value
)
186 if (asprintf (&str
, "%s: %s\n", name
, ctf_strptr (fp
, value
)) < 0)
188 ctf_dump_append (state
, str
);
193 return (ctf_set_errno (fp
, errno
));
196 /* Dump one section-offset field from the file header into the cds_items. */
198 ctf_dump_header_sectfield (ctf_file_t
*fp
, ctf_dump_state_t
*state
,
199 const char *sect
, uint32_t off
, uint32_t nextoff
)
204 if (asprintf (&str
, "%s:\t0x%lx -- 0x%lx (0x%lx bytes)\n", sect
,
205 (unsigned long) off
, (unsigned long) (nextoff
- 1),
206 (unsigned long) (nextoff
- off
)) < 0)
208 ctf_dump_append (state
, str
);
213 return (ctf_set_errno (fp
, errno
));
216 /* Dump the file header into the cds_items. */
218 ctf_dump_header (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
221 const ctf_header_t
*hp
= fp
->ctf_header
;
222 const char *vertab
[] =
224 NULL
, "CTF_VERSION_1",
225 "CTF_VERSION_1_UPGRADED_3 (latest format, version 1 type "
228 "CTF_VERSION_3", NULL
230 const char *verstr
= NULL
;
232 if (asprintf (&str
, "Magic number: %x\n", hp
->cth_magic
) < 0)
234 ctf_dump_append (state
, str
);
236 if (hp
->cth_version
<= CTF_VERSION
)
237 verstr
= vertab
[hp
->cth_version
];
240 verstr
= "(not a valid version)";
242 if (asprintf (&str
, "Version: %i (%s)\n", hp
->cth_version
,
245 ctf_dump_append (state
, str
);
247 /* Everything else is only printed if present. */
249 /* The flags are unusual in that they represent the ctf_file_t *in memory*:
250 flags representing compression, etc, are turned off as the file is
251 decompressed. So we store a copy of the flags before they are changed, for
254 if (fp
->ctf_openflags
> 0)
256 if (fp
->ctf_openflags
)
257 if (asprintf (&str
, "Flags: 0x%x (%s)", fp
->ctf_openflags
,
258 fp
->ctf_openflags
& CTF_F_COMPRESS
? "CTF_F_COMPRESS"
261 ctf_dump_append (state
, str
);
264 if (ctf_dump_header_strfield (fp
, state
, "Parent label",
265 hp
->cth_parlabel
) < 0)
268 if (ctf_dump_header_strfield (fp
, state
, "Parent name", hp
->cth_parname
) < 0)
271 if (ctf_dump_header_strfield (fp
, state
, "Compilation unit name",
275 if (ctf_dump_header_sectfield (fp
, state
, "Label section", hp
->cth_lbloff
,
276 hp
->cth_objtoff
) < 0)
279 if (ctf_dump_header_sectfield (fp
, state
, "Data object section",
280 hp
->cth_objtoff
, hp
->cth_funcoff
) < 0)
283 if (ctf_dump_header_sectfield (fp
, state
, "Function info section",
284 hp
->cth_funcoff
, hp
->cth_varoff
) < 0)
287 if (ctf_dump_header_sectfield (fp
, state
, "Variable section",
288 hp
->cth_varoff
, hp
->cth_typeoff
) < 0)
291 if (ctf_dump_header_sectfield (fp
, state
, "Type section",
292 hp
->cth_typeoff
, hp
->cth_stroff
) < 0)
295 if (ctf_dump_header_sectfield (fp
, state
, "String section", hp
->cth_stroff
,
296 hp
->cth_stroff
+ hp
->cth_strlen
+ 1) < 0)
301 return (ctf_set_errno (fp
, errno
));
304 /* Dump a single label into the cds_items. */
307 ctf_dump_label (const char *name
, const ctf_lblinfo_t
*info
,
312 ctf_dump_state_t
*state
= arg
;
314 if (asprintf (&str
, "%s -> ", name
) < 0)
315 return (ctf_set_errno (state
->cds_fp
, errno
));
317 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, info
->ctb_type
,
318 CTF_ADD_ROOT
)) == NULL
)
321 return -1; /* errno is set for us. */
324 str
= str_append (str
, typestr
);
327 ctf_dump_append (state
, str
);
331 /* Dump all the object entries into the cds_items. (There is no iterator for
332 this section, so we just do it in a loop, and this function handles all of
333 them, rather than only one. */
336 ctf_dump_objts (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
340 for (i
= 0; i
< fp
->ctf_nsyms
; i
++)
344 const char *sym_name
;
347 if ((type
= ctf_lookup_by_symbol (state
->cds_fp
, i
)) == CTF_ERR
)
348 switch (ctf_errno (state
->cds_fp
))
350 /* Most errors are just an indication that this symbol is not a data
351 symbol, but this one indicates that we were called wrong, on a
352 CTF file with no associated symbol table. */
361 sym_name
= ctf_lookup_symbol_name (fp
, i
);
362 if (sym_name
[0] == '\0')
364 if (asprintf (&str
, "%lx -> ", (unsigned long) i
) < 0)
365 return (ctf_set_errno (fp
, errno
));
369 if (asprintf (&str
, "%s (%lx) -> ", sym_name
, (unsigned long) i
) < 0)
370 return (ctf_set_errno (fp
, errno
));
374 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, type
,
375 CTF_ADD_ROOT
)) == NULL
)
378 return -1; /* errno is set for us. */
381 str
= str_append (str
, typestr
);
384 ctf_dump_append (state
, str
);
389 /* Dump all the function entries into the cds_items. (As above, there is no
390 iterator for this section.) */
393 ctf_dump_funcs (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
397 for (i
= 0; i
< fp
->ctf_nsyms
; i
++)
402 const char *sym_name
;
408 if ((type
= ctf_func_info (state
->cds_fp
, i
, &fi
)) == CTF_ERR
)
409 switch (ctf_errno (state
->cds_fp
))
411 /* Most errors are just an indication that this symbol is not a data
412 symbol, but this one indicates that we were called wrong, on a
413 CTF file with no associated symbol table. */
421 if ((args
= calloc (fi
.ctc_argc
, sizeof (ctf_id_t
))) == NULL
)
422 return (ctf_set_errno (fp
, ENOMEM
));
425 if ((str
= ctf_type_aname (state
->cds_fp
, type
)) == NULL
)
427 err
= "look up return type";
431 str
= str_append (str
, " ");
435 sym_name
= ctf_lookup_symbol_name (fp
, i
);
436 if (sym_name
[0] == '\0')
438 if (asprintf (&bit
, "0x%lx ", (unsigned long) i
) < 0)
443 if (asprintf (&bit
, "%s (0x%lx) ", sym_name
, (unsigned long) i
) < 0)
446 str
= str_append (str
, bit
);
447 str
= str_append (str
, " (");
450 /* Function arguments. */
452 if (ctf_func_args (state
->cds_fp
, i
, fi
.ctc_argc
, args
) < 0)
454 err
= "look up argument type";
458 for (j
= 0; j
< fi
.ctc_argc
; j
++)
460 if ((bit
= ctf_type_aname (state
->cds_fp
, args
[j
])) == NULL
)
462 err
= "look up argument type name";
465 str
= str_append (str
, bit
);
466 if ((j
< fi
.ctc_argc
- 1) || (fi
.ctc_flags
& CTF_FUNC_VARARG
))
467 str
= str_append (str
, ", ");
471 if (fi
.ctc_flags
& CTF_FUNC_VARARG
)
472 str
= str_append (str
, "...");
473 str
= str_append (str
, ")");
476 ctf_dump_append (state
, str
);
482 return (ctf_set_errno (fp
, errno
));
484 ctf_dprintf ("Cannot %s dumping function type for symbol 0x%li: %s\n",
485 err
, (unsigned long) i
,
486 ctf_errmsg (ctf_errno (state
->cds_fp
)));
489 return -1; /* errno is set for us. */
494 /* Dump a single variable into the cds_items. */
496 ctf_dump_var (const char *name
, ctf_id_t type
, void *arg
)
500 ctf_dump_state_t
*state
= arg
;
502 if (asprintf (&str
, "%s -> ", name
) < 0)
503 return (ctf_set_errno (state
->cds_fp
, errno
));
505 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, type
,
506 CTF_ADD_ROOT
)) == NULL
)
509 return -1; /* errno is set for us. */
512 str
= str_append (str
, typestr
);
515 ctf_dump_append (state
, str
);
519 /* Dump a single member into the string in the membstate. */
521 ctf_dump_member (const char *name
, ctf_id_t id
, unsigned long offset
,
522 int depth
, void *arg
)
524 ctf_dump_membstate_t
*state
= arg
;
525 char *typestr
= NULL
;
530 for (i
= 0; i
< depth
; i
++)
531 *state
->cdm_str
= str_append (*state
->cdm_str
, " ");
533 if ((typestr
= ctf_type_aname (state
->cdm_fp
, id
)) == NULL
)
535 if (id
== 0 || ctf_errno (state
->cdm_fp
) == ECTF_NONREPRESENTABLE
)
537 if (asprintf (&bit
, " [0x%lx] (type not represented in CTF)",
541 *state
->cdm_str
= str_append (*state
->cdm_str
, bit
);
550 if (asprintf (&bit
, " [0x%lx] (ID 0x%lx) (kind %i) %s %s (aligned at 0x%lx",
551 offset
, id
, ctf_type_kind (state
->cdm_fp
, id
), typestr
, name
,
552 (unsigned long) ctf_type_align (state
->cdm_fp
, id
)) < 0)
554 *state
->cdm_str
= str_append (*state
->cdm_str
, bit
);
560 if ((ctf_type_kind (state
->cdm_fp
, id
) == CTF_K_INTEGER
)
561 || (ctf_type_kind (state
->cdm_fp
, id
) == CTF_K_FLOAT
)
562 || (ctf_is_slice (state
->cdm_fp
, id
, &ep
) == CTF_K_ENUM
))
564 ctf_type_encoding (state
->cdm_fp
, id
, &ep
);
565 if (asprintf (&bit
, ", format 0x%x, offset:bits 0x%x:0x%x", ep
.cte_format
,
566 ep
.cte_offset
, ep
.cte_bits
) < 0)
568 *state
->cdm_str
= str_append (*state
->cdm_str
, bit
);
573 *state
->cdm_str
= str_append (*state
->cdm_str
, ")\n");
579 return (ctf_set_errno (state
->cdm_fp
, errno
));
582 /* Dump a single type into the cds_items. */
584 ctf_dump_type (ctf_id_t id
, int flag
, void *arg
)
588 ctf_dump_state_t
*state
= arg
;
589 ctf_dump_membstate_t membstate
= { &str
, state
->cds_fp
};
592 if ((str
= ctf_dump_format_type (state
->cds_fp
, id
, flag
)) == NULL
)
598 str
= str_append (str
, "\n");
599 if ((ctf_type_visit (state
->cds_fp
, id
, ctf_dump_member
, &membstate
)) < 0)
601 if (id
== 0 || ctf_errno (state
->cds_fp
) == ECTF_NONREPRESENTABLE
)
603 ctf_dump_append (state
, str
);
606 err
= "visit members";
610 /* Trim off the last linefeed added by ctf_dump_member(). */
612 if (str
[len
-1] == '\n')
615 ctf_dump_append (state
, str
);
619 ctf_dprintf ("Cannot %s dumping type 0x%lx: %s\n", err
, id
,
620 ctf_errmsg (ctf_errno (state
->cds_fp
)));
622 return -1; /* errno is set for us. */
625 /* Dump the string table into the cds_items. */
628 ctf_dump_str (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
630 const char *s
= fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
;
632 for (; s
< fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
+
633 fp
->ctf_str
[CTF_STRTAB_0
].cts_len
;)
636 if (asprintf (&str
, "%lx: %s",
637 (unsigned long) (s
- fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
),
639 return (ctf_set_errno (fp
, errno
));
640 ctf_dump_append (state
, str
);
647 /* Dump a particular section of a CTF file, in textual form. Call with a
648 pointer to a NULL STATE: each call emits a dynamically allocated string
649 containing a description of one entity in the specified section, in order.
650 Only the first call (with a NULL state) may vary SECT. Once the CTF section
651 has been entirely dumped, the call returns NULL and frees and annuls the
652 STATE, ready for another section to be dumped. The returned textual content
653 may span multiple lines: between each call the FUNC is called with one
654 textual line at a time, and should return a suitably decorated line (it can
655 allocate a new one and return it if it likes). */
658 ctf_dump (ctf_file_t
*fp
, ctf_dump_state_t
**statep
, ctf_sect_names_t sect
,
659 ctf_dump_decorate_f
*func
, void *arg
)
663 ctf_dump_state_t
*state
= NULL
;
667 /* Data collection. Transforming a call-at-a-time iterator into a
668 return-at-a-time iterator in a language without call/cc is annoying. It
669 is easiest to simply collect everything at once and then return it bit
670 by bit. The first call will take (much) longer than otherwise, but the
671 amortized time needed is the same. */
673 if ((*statep
= malloc (sizeof (struct ctf_dump_state
))) == NULL
)
675 ctf_set_errno (fp
, ENOMEM
);
680 memset (state
, 0, sizeof (struct ctf_dump_state
));
682 state
->cds_sect
= sect
;
686 case CTF_SECT_HEADER
:
687 ctf_dump_header (fp
, state
);
690 if (ctf_label_iter (fp
, ctf_dump_label
, state
) < 0)
692 if (ctf_errno (fp
) != ECTF_NOLABELDATA
)
693 goto end
; /* errno is set for us. */
694 ctf_set_errno (fp
, 0);
698 if (ctf_dump_objts (fp
, state
) < 0)
699 goto end
; /* errno is set for us. */
702 if (ctf_dump_funcs (fp
, state
) < 0)
703 goto end
; /* errno is set for us. */
706 if (ctf_variable_iter (fp
, ctf_dump_var
, state
) < 0)
707 goto end
; /* errno is set for us. */
710 if (ctf_type_iter_all (fp
, ctf_dump_type
, state
) < 0)
711 goto end
; /* errno is set for us. */
714 ctf_dump_str (fp
, state
);
717 ctf_set_errno (fp
, ECTF_DUMPSECTUNKNOWN
);
725 if (state
->cds_sect
!= sect
)
727 ctf_set_errno (fp
, ECTF_DUMPSECTCHANGED
);
732 if (state
->cds_current
== NULL
)
733 state
->cds_current
= ctf_list_next (&state
->cds_items
);
735 state
->cds_current
= ctf_list_next (state
->cds_current
);
737 if (state
->cds_current
== NULL
)
740 /* Hookery. There is some extra complexity to preserve linefeeds within each
741 item while removing linefeeds at the end. */
747 for (line
= state
->cds_current
->cdi_item
; line
&& *line
; )
752 nline
= strchr (line
, '\n');
756 ret
= func (sect
, line
, arg
);
757 str
= str_append (str
, ret
);
758 str
= str_append (str
, "\n");
773 if (str
[len
-1] == '\n')
778 str
= strdup (state
->cds_current
->cdi_item
);
781 ctf_set_errno (fp
, ENOMEM
);
786 ctf_set_errno (fp
, 0);
790 ctf_dump_free (state
);
792 ctf_set_errno (fp
, 0);