1 /* Textual dumping of CTF data.
2 Copyright (C) 2019 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 /* One item to be dumped, in string form. */
25 typedef struct ctf_dump_item
31 /* Cross-call state for dumping. Basically just enough to track the section in
32 use and a list of return strings. */
36 ctf_sect_names_t cds_sect
;
38 ctf_dump_item_t
*cds_current
;
42 /* Cross-call state for ctf_dump_member. */
44 typedef struct ctf_dump_membstate
48 } ctf_dump_membstate_t
;
51 ctf_dump_append (ctf_dump_state_t
*state
, char *str
)
55 if ((cdi
= malloc (sizeof (struct ctf_dump_item
))) == NULL
)
56 return (ctf_set_errno (state
->cds_fp
, ENOMEM
));
59 ctf_list_append (&state
->cds_items
, cdi
);
64 ctf_dump_free (ctf_dump_state_t
*state
)
66 ctf_dump_item_t
*cdi
, *next_cdi
;
71 for (cdi
= ctf_list_next (&state
->cds_items
); cdi
!= NULL
;
75 next_cdi
= ctf_list_next (cdi
);
80 /* Slices need special handling to distinguish them from their referenced
84 ctf_is_slice (ctf_file_t
*fp
, ctf_id_t id
, ctf_encoding_t
*enc
)
86 int kind
= ctf_type_kind (fp
, id
);
88 return (((kind
== CTF_K_INTEGER
) || (kind
== CTF_K_ENUM
)
89 || (kind
== CTF_K_FLOAT
))
90 && ctf_type_reference (fp
, id
) != CTF_ERR
91 && ctf_type_encoding (fp
, id
, enc
) == 0);
94 /* Return a dump for a single type, without member info: but do show the
98 ctf_dump_format_type (ctf_file_t
*fp
, ctf_id_t id
, int flag
)
101 char *str
= NULL
, *bit
= NULL
, *buf
= NULL
;
107 const char *nonroot_leader
= "";
108 const char *nonroot_trailer
= "";
111 if (flag
== CTF_ADD_NONROOT
)
113 nonroot_leader
= "{";
114 nonroot_trailer
= "}";
117 buf
= ctf_type_aname (fp
, id
);
120 if (id
== 0 || ctf_errno (fp
) == ECTF_NONREPRESENTABLE
)
122 str
= ctf_str_append (str
, " (type not represented in CTF)");
123 ctf_set_errno (fp
, ECTF_NOTREF
);
130 /* Slices get a different print representation. */
132 if (ctf_is_slice (fp
, id
, &enc
))
134 ctf_type_encoding (fp
, id
, &enc
);
135 if (asprintf (&bit
, " %s%lx: [slice 0x%x:0x%x]%s",
136 nonroot_leader
, id
, enc
.cte_offset
, enc
.cte_bits
,
137 nonroot_trailer
) < 0)
142 if (asprintf (&bit
, " %s%lx: %s (size 0x%lx)%s", nonroot_leader
,
143 id
, buf
[0] == '\0' ? "(nameless)" : buf
,
144 (unsigned long) ctf_type_size (fp
, id
),
145 nonroot_trailer
) < 0)
150 str
= ctf_str_append (str
, bit
);
154 new_id
= ctf_type_reference (fp
, id
);
155 if (new_id
!= CTF_ERR
)
156 str
= ctf_str_append (str
, " ->");
157 } while (new_id
!= CTF_ERR
);
159 if (ctf_errno (fp
) != ECTF_NOTREF
)
168 ctf_set_errno (fp
, errno
);
176 /* Dump one string field from the file header into the cds_items. */
178 ctf_dump_header_strfield (ctf_file_t
*fp
, ctf_dump_state_t
*state
,
179 const char *name
, uint32_t value
)
184 if (asprintf (&str
, "%s: %s\n", name
, ctf_strptr (fp
, value
)) < 0)
186 ctf_dump_append (state
, str
);
191 return (ctf_set_errno (fp
, errno
));
194 /* Dump one section-offset field from the file header into the cds_items. */
196 ctf_dump_header_sectfield (ctf_file_t
*fp
, ctf_dump_state_t
*state
,
197 const char *sect
, uint32_t off
, uint32_t nextoff
)
202 if (asprintf (&str
, "%s:\t0x%lx -- 0x%lx (0x%lx bytes)\n", sect
,
203 (unsigned long) off
, (unsigned long) (nextoff
- 1),
204 (unsigned long) (nextoff
- off
)) < 0)
206 ctf_dump_append (state
, str
);
211 return (ctf_set_errno (fp
, errno
));
214 /* Dump the file header into the cds_items. */
216 ctf_dump_header (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
219 const ctf_header_t
*hp
= fp
->ctf_header
;
220 const char *vertab
[] =
222 NULL
, "CTF_VERSION_1",
223 "CTF_VERSION_1_UPGRADED_3 (latest format, version 1 type "
226 "CTF_VERSION_3", NULL
228 const char *verstr
= NULL
;
230 if (asprintf (&str
, "Magic number: %x\n", hp
->cth_magic
) < 0)
232 ctf_dump_append (state
, str
);
234 if (hp
->cth_version
<= CTF_VERSION
)
235 verstr
= vertab
[hp
->cth_version
];
238 verstr
= "(not a valid version)";
240 if (asprintf (&str
, "Version: %i (%s)\n", hp
->cth_version
,
243 ctf_dump_append (state
, str
);
245 /* Everything else is only printed if present. */
247 /* The flags are unusual in that they represent the ctf_file_t *in memory*:
248 flags representing compression, etc, are turned off as the file is
249 decompressed. So we store a copy of the flags before they are changed, for
252 if (fp
->ctf_openflags
> 0)
254 if (fp
->ctf_openflags
)
255 if (asprintf (&str
, "Flags: 0x%x (%s)", fp
->ctf_openflags
,
256 fp
->ctf_openflags
& CTF_F_COMPRESS
? "CTF_F_COMPRESS"
259 ctf_dump_append (state
, str
);
262 if (ctf_dump_header_strfield (fp
, state
, "Parent label",
263 hp
->cth_parlabel
) < 0)
266 if (ctf_dump_header_strfield (fp
, state
, "Parent name", hp
->cth_parname
) < 0)
269 if (ctf_dump_header_strfield (fp
, state
, "Compilation unit name",
273 if (ctf_dump_header_sectfield (fp
, state
, "Label section", hp
->cth_lbloff
,
274 hp
->cth_objtoff
) < 0)
277 if (ctf_dump_header_sectfield (fp
, state
, "Data object section",
278 hp
->cth_objtoff
, hp
->cth_funcoff
) < 0)
281 if (ctf_dump_header_sectfield (fp
, state
, "Function info section",
282 hp
->cth_funcoff
, hp
->cth_varoff
) < 0)
285 if (ctf_dump_header_sectfield (fp
, state
, "Variable section",
286 hp
->cth_varoff
, hp
->cth_typeoff
) < 0)
289 if (ctf_dump_header_sectfield (fp
, state
, "Type section",
290 hp
->cth_typeoff
, hp
->cth_stroff
) < 0)
293 if (ctf_dump_header_sectfield (fp
, state
, "String section", hp
->cth_stroff
,
294 hp
->cth_stroff
+ hp
->cth_strlen
+ 1) < 0)
299 return (ctf_set_errno (fp
, errno
));
302 /* Dump a single label into the cds_items. */
305 ctf_dump_label (const char *name
, const ctf_lblinfo_t
*info
,
310 ctf_dump_state_t
*state
= arg
;
312 if (asprintf (&str
, "%s -> ", name
) < 0)
313 return (ctf_set_errno (state
->cds_fp
, errno
));
315 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, info
->ctb_type
,
316 CTF_ADD_ROOT
)) == NULL
)
319 return -1; /* errno is set for us. */
322 str
= ctf_str_append (str
, typestr
);
325 ctf_dump_append (state
, str
);
329 /* Dump all the object entries into the cds_items. (There is no iterator for
330 this section, so we just do it in a loop, and this function handles all of
331 them, rather than only one. */
334 ctf_dump_objts (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
338 for (i
= 0; i
< fp
->ctf_nsyms
; i
++)
342 const char *sym_name
;
345 if ((type
= ctf_lookup_by_symbol (state
->cds_fp
, i
)) == CTF_ERR
)
346 switch (ctf_errno (state
->cds_fp
))
348 /* Most errors are just an indication that this symbol is not a data
349 symbol, but this one indicates that we were called wrong, on a
350 CTF file with no associated symbol table. */
359 sym_name
= ctf_lookup_symbol_name (fp
, i
);
360 if (sym_name
[0] == '\0')
362 if (asprintf (&str
, "%lx -> ", (unsigned long) i
) < 0)
363 return (ctf_set_errno (fp
, errno
));
367 if (asprintf (&str
, "%s (%lx) -> ", sym_name
, (unsigned long) i
) < 0)
368 return (ctf_set_errno (fp
, errno
));
372 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, type
,
373 CTF_ADD_ROOT
)) == NULL
)
376 return -1; /* errno is set for us. */
379 str
= ctf_str_append (str
, typestr
);
382 ctf_dump_append (state
, str
);
387 /* Dump all the function entries into the cds_items. (As above, there is no
388 iterator for this section.) */
391 ctf_dump_funcs (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
395 for (i
= 0; i
< fp
->ctf_nsyms
; i
++)
400 const char *sym_name
;
406 if ((type
= ctf_func_info (state
->cds_fp
, i
, &fi
)) == CTF_ERR
)
407 switch (ctf_errno (state
->cds_fp
))
409 /* Most errors are just an indication that this symbol is not a data
410 symbol, but this one indicates that we were called wrong, on a
411 CTF file with no associated symbol table. */
419 if ((args
= calloc (fi
.ctc_argc
, sizeof (ctf_id_t
))) == NULL
)
420 return (ctf_set_errno (fp
, ENOMEM
));
423 if ((str
= ctf_type_aname (state
->cds_fp
, type
)) == NULL
)
425 err
= "look up return type";
429 str
= ctf_str_append (str
, " ");
433 sym_name
= ctf_lookup_symbol_name (fp
, i
);
434 if (sym_name
[0] == '\0')
436 if (asprintf (&bit
, "0x%lx ", (unsigned long) i
) < 0)
441 if (asprintf (&bit
, "%s (0x%lx) ", sym_name
, (unsigned long) i
) < 0)
444 str
= ctf_str_append (str
, bit
);
445 str
= ctf_str_append (str
, " (");
448 /* Function arguments. */
450 if (ctf_func_args (state
->cds_fp
, i
, fi
.ctc_argc
, args
) < 0)
452 err
= "look up argument type";
456 for (j
= 0; j
< fi
.ctc_argc
; j
++)
458 if ((bit
= ctf_type_aname (state
->cds_fp
, args
[j
])) == NULL
)
460 err
= "look up argument type name";
463 str
= ctf_str_append (str
, bit
);
464 if ((j
< fi
.ctc_argc
- 1) || (fi
.ctc_flags
& CTF_FUNC_VARARG
))
465 str
= ctf_str_append (str
, ", ");
469 if (fi
.ctc_flags
& CTF_FUNC_VARARG
)
470 str
= ctf_str_append (str
, "...");
471 str
= ctf_str_append (str
, ")");
474 ctf_dump_append (state
, str
);
480 return (ctf_set_errno (fp
, errno
));
482 ctf_dprintf ("Cannot %s dumping function type for symbol 0x%li: %s\n",
483 err
, (unsigned long) i
,
484 ctf_errmsg (ctf_errno (state
->cds_fp
)));
487 return -1; /* errno is set for us. */
492 /* Dump a single variable into the cds_items. */
494 ctf_dump_var (const char *name
, ctf_id_t type
, void *arg
)
498 ctf_dump_state_t
*state
= arg
;
500 if (asprintf (&str
, "%s -> ", name
) < 0)
501 return (ctf_set_errno (state
->cds_fp
, errno
));
503 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, type
,
504 CTF_ADD_ROOT
)) == NULL
)
507 return -1; /* errno is set for us. */
510 str
= ctf_str_append (str
, typestr
);
513 ctf_dump_append (state
, str
);
517 /* Dump a single member into the string in the membstate. */
519 ctf_dump_member (const char *name
, ctf_id_t id
, unsigned long offset
,
520 int depth
, void *arg
)
522 ctf_dump_membstate_t
*state
= arg
;
523 char *typestr
= NULL
;
528 for (i
= 0; i
< depth
; i
++)
529 *state
->cdm_str
= ctf_str_append (*state
->cdm_str
, " ");
531 if ((typestr
= ctf_type_aname (state
->cdm_fp
, id
)) == NULL
)
533 if (id
== 0 || ctf_errno (state
->cdm_fp
) == ECTF_NONREPRESENTABLE
)
535 if (asprintf (&bit
, " [0x%lx] (type not represented in CTF)",
539 *state
->cdm_str
= ctf_str_append (*state
->cdm_str
, bit
);
548 if (asprintf (&bit
, " [0x%lx] (ID 0x%lx) (kind %i) %s %s (aligned at 0x%lx",
549 offset
, id
, ctf_type_kind (state
->cdm_fp
, id
), typestr
, name
,
550 (unsigned long) ctf_type_align (state
->cdm_fp
, id
)) < 0)
552 *state
->cdm_str
= ctf_str_append (*state
->cdm_str
, bit
);
558 if ((ctf_type_kind (state
->cdm_fp
, id
) == CTF_K_INTEGER
)
559 || (ctf_type_kind (state
->cdm_fp
, id
) == CTF_K_FLOAT
)
560 || (ctf_is_slice (state
->cdm_fp
, id
, &ep
) == CTF_K_ENUM
))
562 ctf_type_encoding (state
->cdm_fp
, id
, &ep
);
563 if (asprintf (&bit
, ", format 0x%x, offset:bits 0x%x:0x%x", ep
.cte_format
,
564 ep
.cte_offset
, ep
.cte_bits
) < 0)
566 *state
->cdm_str
= ctf_str_append (*state
->cdm_str
, bit
);
571 *state
->cdm_str
= ctf_str_append (*state
->cdm_str
, ")\n");
577 return (ctf_set_errno (state
->cdm_fp
, errno
));
580 /* Dump a single type into the cds_items. */
582 ctf_dump_type (ctf_id_t id
, int flag
, void *arg
)
586 ctf_dump_state_t
*state
= arg
;
587 ctf_dump_membstate_t membstate
= { &str
, state
->cds_fp
};
590 if ((str
= ctf_dump_format_type (state
->cds_fp
, id
, flag
)) == NULL
)
596 str
= ctf_str_append (str
, "\n");
597 if ((ctf_type_visit (state
->cds_fp
, id
, ctf_dump_member
, &membstate
)) < 0)
599 if (id
== 0 || ctf_errno (state
->cds_fp
) == ECTF_NONREPRESENTABLE
)
601 ctf_dump_append (state
, str
);
604 err
= "visit members";
608 /* Trim off the last linefeed added by ctf_dump_member(). */
610 if (str
[len
-1] == '\n')
613 ctf_dump_append (state
, str
);
617 ctf_dprintf ("Cannot %s dumping type 0x%lx: %s\n", err
, id
,
618 ctf_errmsg (ctf_errno (state
->cds_fp
)));
620 return -1; /* errno is set for us. */
623 /* Dump the string table into the cds_items. */
626 ctf_dump_str (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
628 const char *s
= fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
;
630 for (; s
< fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
+
631 fp
->ctf_str
[CTF_STRTAB_0
].cts_len
;)
634 if (asprintf (&str
, "%lx: %s",
635 (unsigned long) (s
- fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
),
637 return (ctf_set_errno (fp
, errno
));
638 ctf_dump_append (state
, str
);
645 /* Dump a particular section of a CTF file, in textual form. Call with a
646 pointer to a NULL STATE: each call emits a dynamically allocated string
647 containing a description of one entity in the specified section, in order.
648 Only the first call (with a NULL state) may vary SECT. Once the CTF section
649 has been entirely dumped, the call returns NULL and frees and annuls the
650 STATE, ready for another section to be dumped. The returned textual content
651 may span multiple lines: between each call the FUNC is called with one
652 textual line at a time, and should return a suitably decorated line (it can
653 allocate a new one and return it if it likes). */
656 ctf_dump (ctf_file_t
*fp
, ctf_dump_state_t
**statep
, ctf_sect_names_t sect
,
657 ctf_dump_decorate_f
*func
, void *arg
)
661 ctf_dump_state_t
*state
= NULL
;
665 /* Data collection. Transforming a call-at-a-time iterator into a
666 return-at-a-time iterator in a language without call/cc is annoying. It
667 is easiest to simply collect everything at once and then return it bit
668 by bit. The first call will take (much) longer than otherwise, but the
669 amortized time needed is the same. */
671 if ((*statep
= malloc (sizeof (struct ctf_dump_state
))) == NULL
)
673 ctf_set_errno (fp
, ENOMEM
);
678 memset (state
, 0, sizeof (struct ctf_dump_state
));
680 state
->cds_sect
= sect
;
684 case CTF_SECT_HEADER
:
685 ctf_dump_header (fp
, state
);
688 if (ctf_label_iter (fp
, ctf_dump_label
, state
) < 0)
690 if (ctf_errno (fp
) != ECTF_NOLABELDATA
)
691 goto end
; /* errno is set for us. */
692 ctf_set_errno (fp
, 0);
696 if (ctf_dump_objts (fp
, state
) < 0)
697 goto end
; /* errno is set for us. */
700 if (ctf_dump_funcs (fp
, state
) < 0)
701 goto end
; /* errno is set for us. */
704 if (ctf_variable_iter (fp
, ctf_dump_var
, state
) < 0)
705 goto end
; /* errno is set for us. */
708 if (ctf_type_iter_all (fp
, ctf_dump_type
, state
) < 0)
709 goto end
; /* errno is set for us. */
712 ctf_dump_str (fp
, state
);
715 ctf_set_errno (fp
, ECTF_DUMPSECTUNKNOWN
);
723 if (state
->cds_sect
!= sect
)
725 ctf_set_errno (fp
, ECTF_DUMPSECTCHANGED
);
730 if (state
->cds_current
== NULL
)
731 state
->cds_current
= ctf_list_next (&state
->cds_items
);
733 state
->cds_current
= ctf_list_next (state
->cds_current
);
735 if (state
->cds_current
== NULL
)
738 /* Hookery. There is some extra complexity to preserve linefeeds within each
739 item while removing linefeeds at the end. */
745 for (line
= state
->cds_current
->cdi_item
; line
&& *line
; )
750 nline
= strchr (line
, '\n');
754 ret
= func (sect
, line
, arg
);
755 str
= ctf_str_append (str
, ret
);
756 str
= ctf_str_append (str
, "\n");
771 if (str
[len
-1] == '\n')
775 str
= strdup (state
->cds_current
->cdi_item
);
777 ctf_set_errno (fp
, 0);
781 ctf_dump_free (state
);
783 ctf_set_errno (fp
, 0);