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 one string field from the file header into the cds_items. */
158 ctf_dump_header_strfield (ctf_file_t
*fp
, ctf_dump_state_t
*state
,
159 const char *name
, uint32_t value
)
164 if (asprintf (&str
, "%s: %s\n", name
, ctf_strptr (fp
, value
)) < 0)
166 ctf_dump_append (state
, str
);
171 return (ctf_set_errno (fp
, -ENOMEM
));
174 /* Dump one section-offset field from the file header into the cds_items. */
176 ctf_dump_header_sectfield (ctf_file_t
*fp
, ctf_dump_state_t
*state
,
177 const char *sect
, uint32_t off
, uint32_t nextoff
)
182 if (asprintf (&str
, "%s:\t0x%lx -- 0x%lx (0x%lx bytes)\n", sect
,
183 (unsigned long) off
, (unsigned long) (nextoff
- 1),
184 (unsigned long) (nextoff
- off
)) < 0)
186 ctf_dump_append (state
, str
);
191 return (ctf_set_errno (fp
, -ENOMEM
));
194 /* Dump the file header into the cds_items. */
196 ctf_dump_header (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
199 const ctf_header_t
*hp
= fp
->ctf_header
;
200 const char *vertab
[] =
202 NULL
, "CTF_VERSION_1",
203 "CTF_VERSION_1_UPGRADED_3 (latest format, version 1 type "
206 "CTF_VERSION_3", NULL
208 const char *verstr
= NULL
;
210 if (asprintf (&str
, "Magic number: %x\n", hp
->cth_magic
) < 0)
212 ctf_dump_append (state
, str
);
214 if (hp
->cth_version
<= CTF_VERSION
)
215 verstr
= vertab
[hp
->cth_version
];
218 verstr
= "(not a valid version)";
220 if (asprintf (&str
, "Version: %i (%s)\n", hp
->cth_version
,
223 ctf_dump_append (state
, str
);
225 /* Everything else is only printed if present. */
227 /* The flags are unusual in that they represent the ctf_file_t *in memory*:
228 flags representing compression, etc, are turned off as the file is
229 decompressed. So we store a copy of the flags before they are changed, for
232 if (fp
->ctf_openflags
> 0)
234 if (fp
->ctf_openflags
)
235 if (asprintf (&str
, "Flags: 0x%x (%s)", fp
->ctf_openflags
,
236 fp
->ctf_openflags
& CTF_F_COMPRESS
? "CTF_F_COMPRESS"
239 ctf_dump_append (state
, str
);
242 if (ctf_dump_header_strfield (fp
, state
, "Parent label",
243 hp
->cth_parlabel
) < 0)
246 if (ctf_dump_header_strfield (fp
, state
, "Parent name", hp
->cth_parname
) < 0)
249 if (ctf_dump_header_strfield (fp
, state
, "Compilation unit name",
253 if (ctf_dump_header_sectfield (fp
, state
, "Label section", hp
->cth_lbloff
,
254 hp
->cth_objtoff
) < 0)
257 if (ctf_dump_header_sectfield (fp
, state
, "Data object section",
258 hp
->cth_objtoff
, hp
->cth_funcoff
) < 0)
261 if (ctf_dump_header_sectfield (fp
, state
, "Function info section",
262 hp
->cth_funcoff
, hp
->cth_varoff
) < 0)
265 if (ctf_dump_header_sectfield (fp
, state
, "Variable section",
266 hp
->cth_varoff
, hp
->cth_typeoff
) < 0)
269 if (ctf_dump_header_sectfield (fp
, state
, "Type section",
270 hp
->cth_typeoff
, hp
->cth_stroff
) < 0)
273 if (ctf_dump_header_sectfield (fp
, state
, "String section", hp
->cth_stroff
,
274 hp
->cth_stroff
+ hp
->cth_strlen
+ 1) < 0)
279 return (ctf_set_errno (fp
, -ENOMEM
));
282 /* Dump a single label into the cds_items. */
285 ctf_dump_label (const char *name
, const ctf_lblinfo_t
*info
,
290 ctf_dump_state_t
*state
= arg
;
292 if (asprintf (&str
, "%s -> ", name
) < 0)
293 return (ctf_set_errno (state
->cds_fp
, ENOMEM
));
295 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, info
->ctb_type
)) == NULL
)
298 return -1; /* errno is set for us. */
301 str
= ctf_str_append (str
, typestr
);
304 ctf_dump_append (state
, str
);
308 /* Dump all the object entries into the cds_items. (There is no iterator for
309 this section, so we just do it in a loop, and this function handles all of
310 them, rather than only one. */
313 ctf_dump_objts (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
317 for (i
= 0; i
< fp
->ctf_nsyms
; i
++)
321 const char *sym_name
;
324 if ((type
= ctf_lookup_by_symbol (state
->cds_fp
, i
)) == CTF_ERR
)
325 switch (ctf_errno (state
->cds_fp
))
327 /* Most errors are just an indication that this symbol is not a data
328 symbol, but this one indicates that we were called wrong, on a
329 CTF file with no associated symbol table. */
338 sym_name
= ctf_lookup_symbol_name (fp
, i
);
339 if (sym_name
[0] == '\0')
341 if (asprintf (&str
, "%lx -> ", (unsigned long) i
) < 0)
342 return (ctf_set_errno (fp
, ENOMEM
));
346 if (asprintf (&str
, "%s (%lx) -> ", sym_name
, (unsigned long) i
) < 0)
347 return (ctf_set_errno (fp
, ENOMEM
));
351 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, type
)) == NULL
)
354 return -1; /* errno is set for us. */
357 str
= ctf_str_append (str
, typestr
);
360 ctf_dump_append (state
, str
);
365 /* Dump all the function entries into the cds_items. (As above, there is no
366 iterator for this section.) */
369 ctf_dump_funcs (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
373 for (i
= 0; i
< fp
->ctf_nsyms
; i
++)
377 const char *sym_name
;
383 if ((type
= ctf_func_info (state
->cds_fp
, i
, &fi
)) == CTF_ERR
)
384 switch (ctf_errno (state
->cds_fp
))
386 /* Most errors are just an indication that this symbol is not a data
387 symbol, but this one indicates that we were called wrong, on a
388 CTF file with no associated symbol table. */
395 if ((args
= calloc (fi
.ctc_argc
, sizeof (ctf_id_t
))) == NULL
)
396 return (ctf_set_errno (fp
, ENOMEM
));
399 if ((str
= ctf_type_aname (state
->cds_fp
, type
)) == NULL
)
402 str
= ctf_str_append (str
, " ");
406 sym_name
= ctf_lookup_symbol_name (fp
, i
);
407 if (sym_name
[0] == '\0')
409 if (asprintf (&bit
, "0x%lx ", (unsigned long) i
) < 0)
414 if (asprintf (&bit
, "%s (0x%lx) ", sym_name
, (unsigned long) i
) < 0)
417 str
= ctf_str_append (str
, bit
);
418 str
= ctf_str_append (str
, " (");
421 /* Function arguments. */
423 if (ctf_func_args (state
->cds_fp
, i
, fi
.ctc_argc
, args
) < 0)
426 for (j
= 0; j
< fi
.ctc_argc
; j
++)
428 if ((bit
= ctf_type_aname (state
->cds_fp
, args
[j
])) == NULL
)
430 str
= ctf_str_append (str
, bit
);
431 if ((j
< fi
.ctc_argc
- 1) || (fi
.ctc_flags
& CTF_FUNC_VARARG
))
432 str
= ctf_str_append (str
, ", ");
436 if (fi
.ctc_flags
& CTF_FUNC_VARARG
)
437 str
= ctf_str_append (str
, "...");
438 str
= ctf_str_append (str
, ")");
441 ctf_dump_append (state
, str
);
447 return (ctf_set_errno (fp
, ENOMEM
));
451 return -1; /* errno is set for us. */
456 /* Dump a single variable into the cds_items. */
458 ctf_dump_var (const char *name
, ctf_id_t type
, void *arg
)
462 ctf_dump_state_t
*state
= arg
;
464 if (asprintf (&str
, "%s -> ", name
) < 0)
465 return (ctf_set_errno (state
->cds_fp
, ENOMEM
));
467 if ((typestr
= ctf_dump_format_type (state
->cds_fp
, type
)) == NULL
)
470 return -1; /* errno is set for us. */
473 str
= ctf_str_append (str
, typestr
);
476 ctf_dump_append (state
, str
);
480 /* Dump a single member into the string in the membstate. */
482 ctf_dump_member (const char *name
, ctf_id_t id
, unsigned long offset
,
483 int depth
, void *arg
)
485 ctf_dump_membstate_t
*state
= arg
;
486 char *typestr
= NULL
;
491 for (i
= 0; i
< depth
; i
++)
492 *state
->cdm_str
= ctf_str_append (*state
->cdm_str
, " ");
494 if ((typestr
= ctf_type_aname (state
->cdm_fp
, id
)) == NULL
)
497 if (asprintf (&bit
, " [0x%lx] (ID 0x%lx) (kind %i) %s %s (aligned at 0x%lx",
498 offset
, id
, ctf_type_kind (state
->cdm_fp
, id
), typestr
, name
,
499 (unsigned long) ctf_type_align (state
->cdm_fp
, id
)) < 0)
501 *state
->cdm_str
= ctf_str_append (*state
->cdm_str
, bit
);
507 if ((ctf_type_kind (state
->cdm_fp
, id
) == CTF_K_INTEGER
)
508 || (ctf_type_kind (state
->cdm_fp
, id
) == CTF_K_FLOAT
)
509 || (ctf_is_slice (state
->cdm_fp
, id
, &ep
) == CTF_K_ENUM
))
511 ctf_type_encoding (state
->cdm_fp
, id
, &ep
);
512 if (asprintf (&bit
, ", format 0x%x, offset:bits 0x%x:0x%x", ep
.cte_format
,
513 ep
.cte_offset
, ep
.cte_bits
) < 0)
515 *state
->cdm_str
= ctf_str_append (*state
->cdm_str
, bit
);
520 *state
->cdm_str
= ctf_str_append (*state
->cdm_str
, ")\n");
526 return (ctf_set_errno (state
->cdm_fp
, ENOMEM
));
529 /* Dump a single type into the cds_items. */
532 ctf_dump_type (ctf_id_t id
, void *arg
)
535 ctf_dump_state_t
*state
= arg
;
536 ctf_dump_membstate_t membstate
= { &str
, state
->cds_fp
};
539 if ((str
= ctf_dump_format_type (state
->cds_fp
, id
)) == NULL
)
542 str
= ctf_str_append (str
, "\n");
543 if ((ctf_type_visit (state
->cds_fp
, id
, ctf_dump_member
, &membstate
)) < 0)
546 /* Trim off the last linefeed added by ctf_dump_member(). */
548 if (str
[len
-1] == '\n')
551 ctf_dump_append (state
, str
);
556 return -1; /* errno is set for us. */
559 /* Dump the string table into the cds_items. */
562 ctf_dump_str (ctf_file_t
*fp
, ctf_dump_state_t
*state
)
564 const char *s
= fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
;
566 for (; s
< fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
+
567 fp
->ctf_str
[CTF_STRTAB_0
].cts_len
;)
570 if (asprintf (&str
, "%lx: %s",
571 (unsigned long) (s
- fp
->ctf_str
[CTF_STRTAB_0
].cts_strs
),
573 return (ctf_set_errno (fp
, ENOMEM
));
574 ctf_dump_append (state
, str
);
581 /* Dump a particular section of a CTF file, in textual form. Call with a
582 pointer to a NULL STATE: each call emits a dynamically allocated string
583 containing a description of one entity in the specified section, in order.
584 Only the first call (with a NULL state) may vary SECT. Once the CTF section
585 has been entirely dumped, the call returns NULL and frees and annuls the
586 STATE, ready for another section to be dumped. The returned textual content
587 may span multiple lines: between each call the FUNC is called with one
588 textual line at a time, and should return a suitably decorated line (it can
589 allocate a new one and return it if it likes). */
592 ctf_dump (ctf_file_t
*fp
, ctf_dump_state_t
**statep
, ctf_sect_names_t sect
,
593 ctf_dump_decorate_f
*func
, void *arg
)
597 ctf_dump_state_t
*state
= NULL
;
601 /* Data collection. Transforming a call-at-a-time iterator into a
602 return-at-a-time iterator in a language without call/cc is annoying. It
603 is easiest to simply collect everything at once and then return it bit
604 by bit. The first call will take (much) longer than otherwise, but the
605 amortized time needed is the same. */
607 if ((*statep
= ctf_alloc (sizeof (struct ctf_dump_state
))) == NULL
)
609 ctf_set_errno (fp
, ENOMEM
);
614 memset (state
, 0, sizeof (struct ctf_dump_state
));
616 state
->cds_sect
= sect
;
620 case CTF_SECT_HEADER
:
621 ctf_dump_header (fp
, state
);
624 if (ctf_label_iter (fp
, ctf_dump_label
, state
) < 0)
626 if (ctf_errno (fp
) != ECTF_NOLABELDATA
)
627 goto end
; /* errno is set for us. */
628 ctf_set_errno (fp
, 0);
632 if (ctf_dump_objts (fp
, state
) < 0)
633 goto end
; /* errno is set for us. */
636 if (ctf_dump_funcs (fp
, state
) < 0)
637 goto end
; /* errno is set for us. */
640 if (ctf_variable_iter (fp
, ctf_dump_var
, state
) < 0)
641 goto end
; /* errno is set for us. */
644 if (ctf_type_iter (fp
, ctf_dump_type
, state
) < 0)
645 goto end
; /* errno is set for us. */
648 ctf_dump_str (fp
, state
);
651 ctf_set_errno (fp
, ECTF_DUMPSECTUNKNOWN
);
659 if (state
->cds_sect
!= sect
)
661 ctf_set_errno (fp
, ECTF_DUMPSECTCHANGED
);
666 if (state
->cds_current
== NULL
)
667 state
->cds_current
= ctf_list_next (&state
->cds_items
);
669 state
->cds_current
= ctf_list_next (state
->cds_current
);
671 if (state
->cds_current
== NULL
)
674 /* Hookery. There is some extra complexity to preserve linefeeds within each
675 item while removing linefeeds at the end. */
681 for (line
= state
->cds_current
->cdi_item
; line
&& *line
; )
686 nline
= strchr (line
, '\n');
690 ret
= func (sect
, line
, arg
);
691 str
= ctf_str_append (str
, ret
);
692 str
= ctf_str_append (str
, "\n");
707 if (str
[len
-1] == '\n')
711 str
= strdup (state
->cds_current
->cdi_item
);
713 ctf_set_errno (fp
, 0);
717 ctf_dump_free (state
);
719 ctf_set_errno (fp
, 0);