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
) == 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
)
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 0x%lx)", id
, buf
[0] == '\0' ?
126 (unsigned long) ctf_type_size (fp
, id
)) < 0)
131 str
= ctf_str_append (str
, bit
);
135 new_id
= ctf_type_reference (fp
, id
);
136 if (new_id
!= CTF_ERR
)
137 str
= ctf_str_append (str
, " ->");
138 } while (new_id
!= CTF_ERR
);
140 if (ctf_errno (fp
) != ECTF_NOTREF
)
152 ctf_set_errno (fp
, ENOMEM
);
156 /* Dump a single label into the cds_items. */
159 ctf_dump_label (const char *name
, const ctf_lblinfo_t
*info
,
164 ctf_dump_state_t
*state
= arg
;
166 if (asprintf (&str
, "%s -> ", name
) < 0)
167 return (ctf_set_errno (state
->cds_fp
, ENOMEM
));
169 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, info
->ctb_type
)) == NULL
)
172 return -1; /* errno is set for us. */
175 str
= ctf_str_append (str
, typestr
);
178 ctf_dump_append (state
, str
);
182 /* Dump all the object entries into the cds_items. (There is no iterator for
183 this section, so we just do it in a loop, and this function handles all of
184 them, rather than only one. */
187 ctf_dump_objts (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
191 for (i
= 0; i
< fp
->ctf_nsyms
; i
++)
195 const char *sym_name
;
198 if ((type
= ctf_lookup_by_symbol (state
->cds_fp
, i
)) == CTF_ERR
)
199 switch (ctf_errno (state
->cds_fp
))
201 /* Most errors are just an indication that this symbol is not a data
202 symbol, but this one indicates that we were called wrong, on a
203 CTF file with no associated symbol table. */
212 sym_name
= ctf_lookup_symbol_name (fp
, i
);
213 if (sym_name
[0] == '\0')
215 if (asprintf (&str
, "%lx -> ", (unsigned long) i
) < 0)
216 return (ctf_set_errno (fp
, ENOMEM
));
220 if (asprintf (&str
, "%s (%lx) -> ", sym_name
, (unsigned long) i
) < 0)
221 return (ctf_set_errno (fp
, ENOMEM
));
225 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, type
)) == NULL
)
228 return -1; /* errno is set for us. */
231 str
= ctf_str_append (str
, typestr
);
234 ctf_dump_append (state
, str
);
239 /* Dump all the function entries into the cds_items. (As above, there is no
240 iterator for this section.) */
243 ctf_dump_funcs (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
247 for (i
= 0; i
< fp
->ctf_nsyms
; i
++)
251 const char *sym_name
;
257 if ((type
= ctf_func_info (state
->cds_fp
, i
, &fi
)) == CTF_ERR
)
258 switch (ctf_errno (state
->cds_fp
))
260 /* Most errors are just an indication that this symbol is not a data
261 symbol, but this one indicates that we were called wrong, on a
262 CTF file with no associated symbol table. */
269 if ((args
= calloc (fi
.ctc_argc
, sizeof (ctf_id_t
))) == NULL
)
270 return (ctf_set_errno (fp
, ENOMEM
));
273 if ((str
= ctf_type_aname (state
->cds_fp
, type
)) == NULL
)
276 str
= ctf_str_append (str
, " ");
280 sym_name
= ctf_lookup_symbol_name (fp
, i
);
281 if (sym_name
[0] == '\0')
283 if (asprintf (&bit
, "0x%lx ", (unsigned long) i
) < 0)
288 if (asprintf (&bit
, "%s (0x%lx) ", sym_name
, (unsigned long) i
) < 0)
291 str
= ctf_str_append (str
, bit
);
292 str
= ctf_str_append (str
, " (");
295 /* Function arguments. */
297 if (ctf_func_args (state
->cds_fp
, i
, fi
.ctc_argc
, args
) < 0)
300 for (j
= 0; j
< fi
.ctc_argc
; j
++)
302 if ((bit
= ctf_type_aname (state
->cds_fp
, args
[j
])) == NULL
)
304 str
= ctf_str_append (str
, bit
);
305 if ((j
< fi
.ctc_argc
- 1) || (fi
.ctc_flags
& CTF_FUNC_VARARG
))
306 str
= ctf_str_append (str
, ", ");
310 if (fi
.ctc_flags
& CTF_FUNC_VARARG
)
311 str
= ctf_str_append (str
, "...");
312 str
= ctf_str_append (str
, ")");
315 ctf_dump_append (state
, str
);
321 return (ctf_set_errno (fp
, ENOMEM
));
325 return -1; /* errno is set for us. */
330 /* Dump a single variable into the cds_items. */
332 ctf_dump_var (const char *name
, ctf_id_t type
, void *arg
)
336 ctf_dump_state_t
*state
= arg
;
338 if (asprintf (&str
, "%s -> ", name
) < 0)
339 return (ctf_set_errno (state
->cds_fp
, ENOMEM
));
341 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, type
)) == NULL
)
344 return -1; /* errno is set for us. */
347 str
= ctf_str_append (str
, typestr
);
350 ctf_dump_append (state
, str
);
354 /* Dump a single member into the string in the membstate. */
356 ctf_dump_member (const char *name
, ctf_id_t id
, unsigned long offset
,
357 int depth
, void *arg
)
359 ctf_dump_membstate_t
*state
= arg
;
360 char *typestr
= NULL
;
365 for (i
= 0; i
< depth
; i
++)
366 *state
->cdm_str
= ctf_str_append (*state
->cdm_str
, " ");
368 if ((typestr
= ctf_type_aname (state
->cdm_fp
, id
)) == NULL
)
371 if (asprintf (&bit
, " [0x%lx] (ID 0x%lx) (kind %i) %s %s (aligned at 0x%lx",
372 offset
, id
, ctf_type_kind (state
->cdm_fp
, id
), typestr
, name
,
373 (unsigned long) ctf_type_align (state
->cdm_fp
, id
)) < 0)
375 *state
->cdm_str
= ctf_str_append (*state
->cdm_str
, bit
);
381 if ((ctf_type_kind (state
->cdm_fp
, id
) == CTF_K_INTEGER
)
382 || (ctf_type_kind (state
->cdm_fp
, id
) == CTF_K_FLOAT
)
383 || (ctf_is_slice (state
->cdm_fp
, id
, &ep
) == CTF_K_ENUM
))
385 ctf_type_encoding (state
->cdm_fp
, id
, &ep
);
386 if (asprintf (&bit
, ", format 0x%x, offset:bits 0x%x:0x%x", ep
.cte_format
,
387 ep
.cte_offset
, ep
.cte_bits
) < 0)
389 *state
->cdm_str
= ctf_str_append (*state
->cdm_str
, bit
);
394 *state
->cdm_str
= ctf_str_append (*state
->cdm_str
, ")\n");
400 return (ctf_set_errno (state
->cdm_fp
, ENOMEM
));
403 /* Dump a single type into the cds_items. */
406 ctf_dump_type (ctf_id_t id
, void *arg
)
409 ctf_dump_state_t
*state
= arg
;
410 ctf_dump_membstate_t membstate
= { &str
, state
->cds_fp
};
413 if ((str
= ctf_dump_format_type (state
->cds_fp
, id
)) == NULL
)
416 str
= ctf_str_append (str
, "\n");
417 if ((ctf_type_visit (state
->cds_fp
, id
, ctf_dump_member
, &membstate
)) < 0)
420 /* Trim off the last linefeed added by ctf_dump_member(). */
422 if (str
[len
-1] == '\n')
425 ctf_dump_append (state
, str
);
430 return -1; /* errno is set for us. */
433 /* Dump the string table into the cds_items. */
436 ctf_dump_str (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
438 const char *s
= fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
;
440 for (; s
< fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
+
441 fp
->ctf_str
[CTF_STRTAB_0
].cts_len
;)
444 if (asprintf (&str
, "%lx: %s",
445 (unsigned long) (s
- fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
),
447 return (ctf_set_errno (fp
, ENOMEM
));
448 ctf_dump_append (state
, str
);
455 /* Dump a particular section of a CTF file, in textual form. Call with a
456 pointer to a NULL STATE: each call emits a dynamically allocated string
457 containing a description of one entity in the specified section, in order.
458 Only the first call (with a NULL state) may vary SECT. Once the CTF section
459 has been entirely dumped, the call returns NULL and frees and annuls the
460 STATE, ready for another section to be dumped. The returned textual content
461 may span multiple lines: between each call the FUNC is called with one
462 textual line at a time, and should return a suitably decorated line (it can
463 allocate a new one and return it if it likes). */
466 ctf_dump (ctf_file_t
*fp
, ctf_dump_state_t
**statep
, ctf_sect_names_t sect
,
467 ctf_dump_decorate_f
*func
, void *arg
)
471 ctf_dump_state_t
*state
= NULL
;
475 /* Data collection. Transforming a call-at-a-time iterator into a
476 return-at-a-time iterator in a language without call/cc is annoying. It
477 is easiest to simply collect everything at once and then return it bit
478 by bit. The first call will take (much) longer than otherwise, but the
479 amortized time needed is the same. */
481 if ((*statep
= ctf_alloc (sizeof (struct ctf_dump_state
))) == NULL
)
483 ctf_set_errno (fp
, ENOMEM
);
488 memset (state
, 0, sizeof (struct ctf_dump_state
));
490 state
->cds_sect
= sect
;
494 case CTF_SECT_HEADER
:
495 /* Nothing doable (yet): entire header is discarded after read-phase. */
499 if (ctf_label_iter (fp
, ctf_dump_label
, state
) < 0)
501 if (ctf_errno (fp
) != ECTF_NOLABELDATA
)
502 goto end
; /* errno is set for us. */
503 ctf_set_errno (fp
, 0);
507 if (ctf_dump_objts (fp
, state
) < 0)
508 goto end
; /* errno is set for us. */
511 if (ctf_dump_funcs (fp
, state
) < 0)
512 goto end
; /* errno is set for us. */
515 if (ctf_variable_iter (fp
, ctf_dump_var
, state
) < 0)
516 goto end
; /* errno is set for us. */
519 if (ctf_type_iter (fp
, ctf_dump_type
, state
) < 0)
520 goto end
; /* errno is set for us. */
523 ctf_dump_str (fp
, state
);
526 ctf_set_errno (fp
, ECTF_DUMPSECTUNKNOWN
);
534 if (state
->cds_sect
!= sect
)
536 ctf_set_errno (fp
, ECTF_DUMPSECTCHANGED
);
541 if (state
->cds_current
== NULL
)
542 state
->cds_current
= ctf_list_next (&state
->cds_items
);
544 state
->cds_current
= ctf_list_next (state
->cds_current
);
546 if (state
->cds_current
== NULL
)
549 /* Hookery. There is some extra complexity to preserve linefeeds within each
550 item while removing linefeeds at the end. */
556 for (line
= state
->cds_current
->cdi_item
; line
&& *line
; )
561 nline
= strchr (line
, '\n');
565 ret
= func (sect
, line
, arg
);
566 str
= ctf_str_append (str
, ret
);
567 str
= ctf_str_append (str
, "\n");
582 if (str
[len
-1] == '\n')
586 str
= strdup (state
->cds_current
->cdi_item
);
588 ctf_set_errno (fp
, 0);
592 ctf_dump_free (state
);
594 ctf_set_errno (fp
, 0);