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 = ctf_alloc (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) != CTF_ERR);
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)
101 char *str = NULL, *bit = NULL, *buf = NULL;
109 buf = ctf_type_aname (fp, id);
113 /* Slices get a different print representation. */
115 if (ctf_is_slice (fp, id, &enc))
117 ctf_type_encoding (fp, id, &enc);
118 if (asprintf (&bit, " %lx: [slice 0x%x:0x%x]",
119 id, enc.cte_offset, enc.cte_bits) < 0)
124 if (asprintf (&bit, " %lx: %s (size %lx)", id, buf[0] == '\0' ?
125 "(nameless)" : buf, ctf_type_size (fp, id)) < 0)
130 str = ctf_str_append (str, bit);
134 new_id = ctf_type_reference (fp, id);
135 if (new_id != CTF_ERR)
136 str = ctf_str_append (str, " ->");
137 } while (new_id != CTF_ERR);
139 if (ctf_errno (fp) != ECTF_NOTREF)
151 ctf_set_errno (fp, ENOMEM);
155 /* Dump a single label into the cds_items. */
158 ctf_dump_label (const char *name, const ctf_lblinfo_t *info,
163 ctf_dump_state_t *state = arg;
165 if (asprintf (&str, "%s -> ", name) < 0)
166 return (ctf_set_errno (state->cds_fp, ENOMEM));
168 if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type)) == NULL)
171 return CTF_ERR; /* errno is set for us. */
174 str = ctf_str_append (str, typestr);
177 ctf_dump_append (state, str);
181 /* Dump all the object entries into the cds_items. (There is no iterator for
182 this section, so we just do it in a loop, and this function handles all of
183 them, rather than only one. */
186 ctf_dump_objts (ctf_file_t *fp, ctf_dump_state_t *state)
190 for (i = 0; i < fp->ctf_nsyms; i++)
194 const char *sym_name;
197 if ((type = ctf_lookup_by_symbol (state->cds_fp, i)) < 0)
198 switch (ctf_errno (state->cds_fp))
200 /* Most errors are just an indication that this symbol is not a data
201 symbol, but this one indicates that we were called wrong, on a
202 CTF file with no associated symbol table. */
211 sym_name = ctf_lookup_symbol_name (fp, i);
212 if (sym_name[0] == '\0')
214 if (asprintf (&str, "%lx -> ", i) < 0)
215 return (ctf_set_errno (fp, ENOMEM));
219 if (asprintf (&str, "%s (%lx) -> ", sym_name, i) < 0)
220 return (ctf_set_errno (fp, ENOMEM));
224 if ((typestr = ctf_dump_format_type (state->cds_fp, type)) == NULL)
227 return CTF_ERR; /* errno is set for us. */
230 str = ctf_str_append (str, typestr);
233 ctf_dump_append (state, str);
238 /* Dump all the function entries into the cds_items. (As above, there is no
239 iterator for this section.) */
242 ctf_dump_funcs (ctf_file_t *fp, ctf_dump_state_t *state)
246 for (i = 0; i < fp->ctf_nsyms; i++)
250 const char *sym_name;
256 if ((type = ctf_func_info (state->cds_fp, i, &fi)) < 0)
257 switch (ctf_errno (state->cds_fp))
259 /* Most errors are just an indication that this symbol is not a data
260 symbol, but this one indicates that we were called wrong, on a
261 CTF file with no associated symbol table. */
268 if ((args = calloc (fi.ctc_argc, sizeof (ctf_id_t))) == NULL)
269 return (ctf_set_errno (fp, ENOMEM));
272 if ((str = ctf_type_aname (state->cds_fp, type)) == NULL)
275 str = ctf_str_append (str, " ");
280 sym_name = ctf_lookup_symbol_name (fp, i);
281 if (sym_name[0] == '\0')
283 if (asprintf (&bit, "%lx ", i) < 0)
288 if (asprintf (&bit, "%s (%lx) ", sym_name, i) < 0)
291 str = ctf_str_append (str, bit);
292 str = ctf_str_append (str, " (");
294 /* Function arguments. */
296 if (ctf_func_args (state->cds_fp, i, fi.ctc_argc, args) < 0)
299 for (j = 0; j < fi.ctc_argc; j++)
301 if ((bit = ctf_type_aname (state->cds_fp, args[j])) == NULL)
303 str = ctf_str_append (str, bit);
304 if ((j < fi.ctc_argc - 1) || (fi.ctc_flags & CTF_FUNC_VARARG))
305 str = ctf_str_append (str, ", ");
309 if (fi.ctc_flags & CTF_FUNC_VARARG)
310 str = ctf_str_append (str, "...");
311 str = ctf_str_append (str, ")");
314 ctf_dump_append (state, str);
320 return (ctf_set_errno (fp, ENOMEM));
324 return CTF_ERR; /* errno is set for us. */
329 /* Dump a single variable into the cds_items. */
331 ctf_dump_var (const char *name, ctf_id_t type, void *arg)
335 ctf_dump_state_t *state = arg;
337 if (asprintf (&str, "%s -> ", name) < 0)
338 return (ctf_set_errno (state->cds_fp, ENOMEM));
340 if ((typestr = ctf_dump_format_type (state->cds_fp, type)) == NULL)
343 return CTF_ERR; /* errno is set for us. */
346 str = ctf_str_append (str, typestr);
349 ctf_dump_append (state, str);
353 /* Dump a single member into the string in the membstate. */
355 ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
356 int depth, void *arg)
358 ctf_dump_membstate_t *state = arg;
359 char *typestr = NULL;
364 for (i = 0; i < depth; i++)
365 *state->cdm_str = ctf_str_append (*state->cdm_str, " ");
367 if ((typestr = ctf_type_aname (state->cdm_fp, id)) == NULL)
370 if (asprintf (&bit, " [0x%lx] (ID 0x%lx) (kind %i) %s %s (aligned at 0x%lx",
371 offset, id, ctf_type_kind (state->cdm_fp, id), typestr, name,
372 ctf_type_align (state->cdm_fp, id)) < 0)
374 *state->cdm_str = ctf_str_append (*state->cdm_str, bit);
380 if ((ctf_type_kind (state->cdm_fp, id) == CTF_K_INTEGER)
381 || (ctf_type_kind (state->cdm_fp, id) == CTF_K_FLOAT)
382 || (ctf_is_slice (state->cdm_fp, id, &ep) == CTF_K_ENUM))
384 ctf_type_encoding (state->cdm_fp, id, &ep);
385 if (asprintf (&bit, ", format 0x%x, offset:bits 0x%x:0x%x", ep.cte_format,
386 ep.cte_offset, ep.cte_bits) < 0)
388 *state->cdm_str = ctf_str_append (*state->cdm_str, bit);
393 *state->cdm_str = ctf_str_append (*state->cdm_str, ")\n");
399 return (ctf_set_errno (state->cdm_fp, ENOMEM));
402 /* Dump a single type into the cds_items. */
405 ctf_dump_type (ctf_id_t id, void *arg)
408 ctf_dump_state_t *state = arg;
409 ctf_dump_membstate_t membstate = { &str, state->cds_fp };
412 if ((str = ctf_dump_format_type (state->cds_fp, id)) == NULL)
415 str = ctf_str_append (str, "\n");
416 if ((ctf_type_visit (state->cds_fp, id, ctf_dump_member, &membstate)) < 0)
419 /* Trim off the last linefeed added by ctf_dump_member(). */
421 if (str[len-1] == '\n')
424 ctf_dump_append (state, str);
429 return CTF_ERR; /* errno is set for us. */
432 /* Dump the string table into the cds_items. */
435 ctf_dump_str (ctf_file_t *fp, ctf_dump_state_t *state)
437 const char *s = fp->ctf_str[CTF_STRTAB_0].cts_strs;
439 for (; s < fp->ctf_str[CTF_STRTAB_0].cts_strs +
440 fp->ctf_str[CTF_STRTAB_0].cts_len;)
443 if (asprintf (&str, "%lx: %s", s - fp->ctf_str[CTF_STRTAB_0].cts_strs,
445 return (ctf_set_errno (fp, ENOMEM));
446 ctf_dump_append (state, str);
453 /* Dump a particular section of a CTF file, in textual form. Call with a
454 pointer to a NULL STATE: each call emits a dynamically allocated string
455 containing a description of one entity in the specified section, in order.
456 Only the first call (with a NULL state) may vary SECT. Once the CTF section
457 has been entirely dumped, the call returns NULL and frees and annuls the
458 STATE, ready for another section to be dumped. The returned textual content
459 may span multiple lines: between each call the FUNC is called with one
460 textual line at a time, and should return a suitably decorated line (it can
461 allocate a new one and return it if it likes). */
464 ctf_dump (ctf_file_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
465 ctf_dump_decorate_f *func, void *arg)
469 ctf_dump_state_t *state = NULL;
473 /* Data collection. Transforming a call-at-a-time iterator into a
474 return-at-a-time iterator in a language without call/cc is annoying. It
475 is easiest to simply collect everything at once and then return it bit
476 by bit. The first call will take (much) longer than otherwise, but the
477 amortized time needed is the same. */
479 if ((*statep = ctf_alloc (sizeof (struct ctf_dump_state))) == NULL)
481 ctf_set_errno (fp, ENOMEM);
486 memset (state, 0, sizeof (struct ctf_dump_state));
488 state->cds_sect = sect;
492 case CTF_SECT_HEADER:
493 /* Nothing doable (yet): entire header is discarded after read-phase. */
497 if (ctf_label_iter (fp, ctf_dump_label, state) < 0)
499 if (ctf_errno (fp) != ECTF_NOLABELDATA)
500 goto end; /* errno is set for us. */
501 ctf_set_errno (fp, 0);
505 if (ctf_dump_objts (fp, state) < 0)
506 goto end; /* errno is set for us. */
509 if (ctf_dump_funcs (fp, state) < 0)
510 goto end; /* errno is set for us. */
513 if (ctf_variable_iter (fp, ctf_dump_var, state) < 0)
514 goto end; /* errno is set for us. */
517 if (ctf_type_iter (fp, ctf_dump_type, state) < 0)
518 goto end; /* errno is set for us. */
521 ctf_dump_str (fp, state);
524 ctf_set_errno (fp, ECTF_DUMPSECTUNKNOWN);
532 if (state->cds_sect != sect)
534 ctf_set_errno (fp, ECTF_DUMPSECTCHANGED);
539 if (state->cds_current == NULL)
540 state->cds_current = ctf_list_next (&state->cds_items);
542 state->cds_current = ctf_list_next (state->cds_current);
544 if (state->cds_current == NULL)
547 /* Hookery. There is some extra complexity to preserve linefeeds within each
548 item while removing linefeeds at the end. */
554 for (line = state->cds_current->cdi_item; line && *line; )
559 nline = strchr (line, '\n');
563 ret = func (sect, line, arg);
564 str = ctf_str_append (str, ret);
565 str = ctf_str_append (str, "\n");
580 if (str[len-1] == '\n')
584 str = strdup (state->cds_current->cdi_item);
586 ctf_set_errno (fp, 0);
590 ctf_dump_free (state);
592 ctf_set_errno (fp, 0);