Update copyright year range in all GDB files
[binutils-gdb.git] / libctf / ctf-dump.c
blob621ff25b98320b6699b5347ffd1bf3745a588730
1 /* Textual dumping of CTF data.
2 Copyright (C) 2019-2021 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
9 version.
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/>. */
20 #include <ctf-impl.h>
21 #include <string.h>
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
29 ctf_list_t cdi_list;
30 char *cdi_item;
31 } ctf_dump_item_t;
33 /* Cross-call state for dumping. Basically just enough to track the section in
34 use and a list of return strings. */
36 struct ctf_dump_state
38 ctf_sect_names_t cds_sect;
39 ctf_dict_t *cds_fp;
40 ctf_dump_item_t *cds_current;
41 ctf_list_t cds_items;
44 /* Cross-call state for ctf_dump_member. */
46 typedef struct ctf_dump_membstate
48 char **cdm_str;
49 ctf_dict_t *cdm_fp;
50 } ctf_dump_membstate_t;
52 static int
53 ctf_dump_append (ctf_dump_state_t *state, char *str)
55 ctf_dump_item_t *cdi;
57 if ((cdi = malloc (sizeof (struct ctf_dump_item))) == NULL)
58 return (ctf_set_errno (state->cds_fp, ENOMEM));
60 cdi->cdi_item = str;
61 ctf_list_append (&state->cds_items, cdi);
62 return 0;
65 static void
66 ctf_dump_free (ctf_dump_state_t *state)
68 ctf_dump_item_t *cdi, *next_cdi;
70 if (state == NULL)
71 return;
73 for (cdi = ctf_list_next (&state->cds_items); cdi != NULL;
74 cdi = next_cdi)
76 free (cdi->cdi_item);
77 next_cdi = ctf_list_next (cdi);
78 free (cdi);
82 /* Return a dump for a single type, without member info: but do show the
83 type's references. */
85 static char *
86 ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
88 ctf_id_t new_id;
89 char *str = NULL, *bit = NULL, *buf = NULL;
91 new_id = id;
94 ctf_encoding_t enc;
95 const char *nonroot_leader = "";
96 const char *nonroot_trailer = "";
98 id = new_id;
99 if (flag == CTF_ADD_NONROOT)
101 nonroot_leader = "{";
102 nonroot_trailer = "}";
105 buf = ctf_type_aname (fp, id);
106 if (!buf)
108 if (id == 0 || ctf_errno (fp) == ECTF_NONREPRESENTABLE)
110 str = str_append (str, " (type not represented in CTF)");
111 ctf_set_errno (fp, ECTF_NOTREF);
112 break;
115 goto err;
118 if (asprintf (&bit, " %s%lx: ", nonroot_leader, id) < 0)
119 goto oom;
120 str = str_append (str, bit);
121 free (bit);
122 bit = NULL;
124 if (buf[0] != '\0')
126 str = str_append (str, buf);
127 str = str_append (str, " ");
130 free (buf);
131 buf = NULL;
133 /* Slices get a different print representation. */
134 if (ctf_type_kind_unsliced (fp, id) == CTF_K_SLICE)
136 ctf_type_encoding (fp, id, &enc);
137 if (asprintf (&bit, "[slice 0x%x:0x%x] ",
138 enc.cte_offset, enc.cte_bits) < 0)
139 goto oom;
141 else if (ctf_type_kind (fp, id) == CTF_K_INTEGER)
143 ctf_type_encoding (fp, id, &enc);
144 if (asprintf (&bit, "[0x%x:0x%x] ",
145 enc.cte_offset, enc.cte_bits) < 0)
146 goto oom;
148 str = str_append (str, bit);
149 free (bit);
150 bit = NULL;
152 if (asprintf (&bit, "(size 0x%lx)%s",
153 (unsigned long) ctf_type_size (fp, id),
154 nonroot_trailer) < 0)
155 goto oom;
157 str = str_append (str, bit);
158 free (bit);
159 bit = NULL;
161 new_id = ctf_type_reference (fp, id);
162 if (new_id != CTF_ERR)
163 str = str_append (str, " ->");
164 } while (new_id != CTF_ERR);
166 if (ctf_errno (fp) != ECTF_NOTREF)
168 free (str);
169 return NULL;
172 return str;
174 oom:
175 ctf_set_errno (fp, errno);
176 err:
177 ctf_err_warn (fp, 1, 0, _("cannot format name dumping type 0x%lx"), id);
178 free (buf);
179 free (str);
180 free (bit);
181 return NULL;
184 /* Dump one string field from the file header into the cds_items. */
185 static int
186 ctf_dump_header_strfield (ctf_dict_t *fp, ctf_dump_state_t *state,
187 const char *name, uint32_t value)
189 char *str;
190 if (value)
192 if (asprintf (&str, "%s: %s\n", name, ctf_strptr (fp, value)) < 0)
193 goto err;
194 ctf_dump_append (state, str);
196 return 0;
198 err:
199 return (ctf_set_errno (fp, errno));
202 /* Dump one section-offset field from the file header into the cds_items. */
203 static int
204 ctf_dump_header_sectfield (ctf_dict_t *fp, ctf_dump_state_t *state,
205 const char *sect, uint32_t off, uint32_t nextoff)
207 char *str;
208 if (nextoff - off)
210 if (asprintf (&str, "%s:\t0x%lx -- 0x%lx (0x%lx bytes)\n", sect,
211 (unsigned long) off, (unsigned long) (nextoff - 1),
212 (unsigned long) (nextoff - off)) < 0)
213 goto err;
214 ctf_dump_append (state, str);
216 return 0;
218 err:
219 return (ctf_set_errno (fp, errno));
222 /* Dump the file header into the cds_items. */
223 static int
224 ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
226 char *str;
227 char *flagstr = NULL;
228 const ctf_header_t *hp = fp->ctf_header;
229 const char *vertab[] =
231 NULL, "CTF_VERSION_1",
232 "CTF_VERSION_1_UPGRADED_3 (latest format, version 1 type "
233 "boundaries)",
234 "CTF_VERSION_2",
235 "CTF_VERSION_3", NULL
237 const char *verstr = NULL;
239 if (asprintf (&str, "Magic number: %x\n", hp->cth_magic) < 0)
240 goto err;
241 ctf_dump_append (state, str);
243 if (hp->cth_version <= CTF_VERSION)
244 verstr = vertab[hp->cth_version];
246 if (verstr == NULL)
247 verstr = "(not a valid version)";
249 if (asprintf (&str, "Version: %i (%s)\n", hp->cth_version,
250 verstr) < 0)
251 goto err;
252 ctf_dump_append (state, str);
254 /* Everything else is only printed if present. */
256 /* The flags are unusual in that they represent the ctf_dict_t *in memory*:
257 flags representing compression, etc, are turned off as the file is
258 decompressed. So we store a copy of the flags before they are changed, for
259 the dumper. */
261 if (fp->ctf_openflags > 0)
263 if (asprintf (&flagstr, "%s%s%s%s%s%s%s",
264 fp->ctf_openflags & CTF_F_COMPRESS
265 ? "CTF_F_COMPRESS": "",
266 (fp->ctf_openflags & CTF_F_COMPRESS)
267 && (fp->ctf_openflags & ~CTF_F_COMPRESS)
268 ? ", " : "",
269 fp->ctf_openflags & CTF_F_NEWFUNCINFO
270 ? "CTF_F_NEWFUNCINFO" : "",
271 (fp->ctf_openflags & (CTF_F_COMPRESS | CTF_F_NEWFUNCINFO))
272 && (fp->ctf_openflags & ~(CTF_F_COMPRESS | CTF_F_NEWFUNCINFO))
273 ? ", " : "",
274 fp->ctf_openflags & CTF_F_IDXSORTED
275 ? "CTF_F_IDXSORTED" : "",
276 fp->ctf_openflags & (CTF_F_COMPRESS | CTF_F_NEWFUNCINFO
277 | CTF_F_IDXSORTED)
278 && (fp->ctf_openflags & ~(CTF_F_COMPRESS | CTF_F_NEWFUNCINFO
279 | CTF_F_IDXSORTED))
280 ? ", " : "",
281 fp->ctf_openflags & CTF_F_DYNSTR
282 ? "CTF_F_DYNSTR" : "") < 0)
283 goto err;
285 if (asprintf (&str, "Flags: 0x%x (%s)", fp->ctf_openflags, flagstr) < 0)
286 goto err;
287 ctf_dump_append (state, str);
290 if (ctf_dump_header_strfield (fp, state, "Parent label",
291 hp->cth_parlabel) < 0)
292 goto err;
294 if (ctf_dump_header_strfield (fp, state, "Parent name", hp->cth_parname) < 0)
295 goto err;
297 if (ctf_dump_header_strfield (fp, state, "Compilation unit name",
298 hp->cth_cuname) < 0)
299 goto err;
301 if (ctf_dump_header_sectfield (fp, state, "Label section", hp->cth_lbloff,
302 hp->cth_objtoff) < 0)
303 goto err;
305 if (ctf_dump_header_sectfield (fp, state, "Data object section",
306 hp->cth_objtoff, hp->cth_funcoff) < 0)
307 goto err;
309 if (ctf_dump_header_sectfield (fp, state, "Function info section",
310 hp->cth_funcoff, hp->cth_objtidxoff) < 0)
311 goto err;
313 if (ctf_dump_header_sectfield (fp, state, "Object index section",
314 hp->cth_objtidxoff, hp->cth_funcidxoff) < 0)
315 goto err;
317 if (ctf_dump_header_sectfield (fp, state, "Function index section",
318 hp->cth_funcidxoff, hp->cth_varoff) < 0)
319 goto err;
321 if (ctf_dump_header_sectfield (fp, state, "Variable section",
322 hp->cth_varoff, hp->cth_typeoff) < 0)
323 goto err;
325 if (ctf_dump_header_sectfield (fp, state, "Type section",
326 hp->cth_typeoff, hp->cth_stroff) < 0)
327 goto err;
329 if (ctf_dump_header_sectfield (fp, state, "String section", hp->cth_stroff,
330 hp->cth_stroff + hp->cth_strlen + 1) < 0)
331 goto err;
333 return 0;
334 err:
335 free (flagstr);
336 return (ctf_set_errno (fp, errno));
339 /* Dump a single label into the cds_items. */
341 static int
342 ctf_dump_label (const char *name, const ctf_lblinfo_t *info,
343 void *arg)
345 char *str;
346 char *typestr;
347 ctf_dump_state_t *state = arg;
349 if (asprintf (&str, "%s -> ", name) < 0)
350 return (ctf_set_errno (state->cds_fp, errno));
352 if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type,
353 CTF_ADD_ROOT)) == NULL)
355 free (str);
356 return 0; /* Swallow the error. */
359 str = str_append (str, typestr);
360 free (typestr);
362 ctf_dump_append (state, str);
363 return 0;
366 /* Dump all the object or function entries into the cds_items. */
368 static int
369 ctf_dump_objts (ctf_dict_t *fp, ctf_dump_state_t *state, int functions)
371 const char *name;
372 ctf_id_t id;
373 ctf_next_t *i = NULL;
374 char *str = NULL;
376 if ((functions && fp->ctf_funcidx_names)
377 || (!functions && fp->ctf_objtidx_names))
378 str = str_append (str, _("Section is indexed.\n"));
379 else if (fp->ctf_symtab.cts_data == NULL)
380 str = str_append (str, _("No symbol table.\n"));
382 while ((id = ctf_symbol_next (fp, &i, &name, functions)) != CTF_ERR)
384 char *typestr = NULL;
385 int err = 0;
387 /* Emit the name, if we know it. */
388 if (name)
390 if (asprintf (&str, "%s -> ", name) < 0)
391 goto oom;
393 else
394 str = xstrdup ("");
396 if ((typestr = ctf_type_aname (fp, id)) == NULL)
398 if (id == 0 || ctf_errno (fp) == ECTF_NONREPRESENTABLE)
400 if (asprintf (&typestr, " (%s)", _("type not represented in CTF")) < 0)
401 goto oom;
403 goto out;
406 if (asprintf (&typestr, _("error: %s"), ctf_errmsg (ctf_errno (fp))) < 0)
407 goto oom;
409 err = -1;
410 goto out;
413 str = str_append (str, typestr);
414 str = str_append (str, "\n");
415 ctf_dump_append (state, str);
416 continue;
418 oom:
419 ctf_set_errno (fp, ENOMEM);
420 ctf_next_destroy (i);
421 return -1;
422 out:
423 str = str_append (str, typestr);
424 free (typestr);
425 ctf_dump_append (state, str);
426 ctf_next_destroy (i);
427 return err; /* errno is set for us. */
429 return 0;
432 /* Dump a single variable into the cds_items. */
433 static int
434 ctf_dump_var (const char *name, ctf_id_t type, void *arg)
436 char *str;
437 char *typestr;
438 ctf_dump_state_t *state = arg;
440 if (asprintf (&str, "%s -> ", name) < 0)
441 return (ctf_set_errno (state->cds_fp, errno));
443 if ((typestr = ctf_dump_format_type (state->cds_fp, type,
444 CTF_ADD_ROOT)) == NULL)
446 free (str);
447 return 0; /* Swallow the error. */
450 str = str_append (str, typestr);
451 free (typestr);
453 ctf_dump_append (state, str);
454 return 0;
457 /* Dump a single member into the string in the membstate. */
458 static int
459 ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
460 int depth, void *arg)
462 ctf_dump_membstate_t *state = arg;
463 char *typestr = NULL;
464 char *bit = NULL;
465 ctf_encoding_t ep;
466 int has_encoding = 0;
467 ssize_t i;
469 for (i = 0; i < depth; i++)
470 *state->cdm_str = str_append (*state->cdm_str, " ");
472 if ((typestr = ctf_type_aname (state->cdm_fp, id)) == NULL)
474 if (id == 0 || ctf_errno (state->cdm_fp) == ECTF_NONREPRESENTABLE)
476 if (asprintf (&bit, " [0x%lx] (type not represented in CTF)",
477 offset) < 0)
478 goto oom;
480 *state->cdm_str = str_append (*state->cdm_str, bit);
481 free (typestr);
482 free (bit);
483 return 0;
486 return -1; /* errno is set for us. */
489 if (ctf_type_encoding (state->cdm_fp, id, &ep) == 0)
491 has_encoding = 1;
492 ctf_type_encoding (state->cdm_fp, id, &ep);
494 if (asprintf (&bit, " [0x%lx] (ID 0x%lx) (kind %i) %s%s%s:%i "
495 "(aligned at 0x%lx", offset, id,
496 ctf_type_kind (state->cdm_fp, id), typestr,
497 (name[0] != 0 && typestr[0] != 0) ? " " : "", name,
498 ep.cte_bits, (unsigned long) ctf_type_align (state->cdm_fp,
499 id)) < 0)
500 goto oom;
502 else
504 if (asprintf (&bit, " [0x%lx] (ID 0x%lx) (kind %i) %s%s%s "
505 "(aligned at 0x%lx", offset, id,
506 ctf_type_kind (state->cdm_fp, id), typestr,
507 (name[0] != 0 && typestr[0] != 0) ? " " : "", name,
508 (unsigned long) ctf_type_align (state->cdm_fp, id)) < 0)
509 goto oom;
512 *state->cdm_str = str_append (*state->cdm_str, bit);
513 free (typestr);
514 free (bit);
515 typestr = NULL;
516 bit = NULL;
518 if (has_encoding)
520 if (asprintf (&bit, ", format 0x%x, offset:bits 0x%x:0x%x", ep.cte_format,
521 ep.cte_offset, ep.cte_bits) < 0)
522 goto oom;
523 *state->cdm_str = str_append (*state->cdm_str, bit);
524 free (bit);
525 bit = NULL;
528 *state->cdm_str = str_append (*state->cdm_str, ")\n");
529 return 0;
531 oom:
532 free (typestr);
533 free (bit);
534 return (ctf_set_errno (state->cdm_fp, errno));
537 /* Dump a single type into the cds_items. */
538 static int
539 ctf_dump_type (ctf_id_t id, int flag, void *arg)
541 char *str;
542 ctf_dump_state_t *state = arg;
543 ctf_dump_membstate_t membstate = { &str, state->cds_fp };
544 size_t len;
546 if ((str = ctf_dump_format_type (state->cds_fp, id, flag)) == NULL)
547 goto err;
549 str = str_append (str, "\n");
550 if ((ctf_type_visit (state->cds_fp, id, ctf_dump_member, &membstate)) < 0)
552 if (id == 0 || ctf_errno (state->cds_fp) == ECTF_NONREPRESENTABLE)
554 ctf_dump_append (state, str);
555 return 0;
557 ctf_err_warn (state->cds_fp, 1, ctf_errno (state->cds_fp),
558 _("cannot visit members dumping type 0x%lx"), id);
559 goto err;
562 /* Trim off the last linefeed added by ctf_dump_member(). */
563 len = strlen (str);
564 if (str[len-1] == '\n')
565 str[len-1] = '\0';
567 ctf_dump_append (state, str);
568 return 0;
570 err:
571 free (str);
572 return 0; /* Swallow the error. */
575 /* Dump the string table into the cds_items. */
577 static int
578 ctf_dump_str (ctf_dict_t *fp, ctf_dump_state_t *state)
580 const char *s = fp->ctf_str[CTF_STRTAB_0].cts_strs;
582 for (; s < fp->ctf_str[CTF_STRTAB_0].cts_strs +
583 fp->ctf_str[CTF_STRTAB_0].cts_len;)
585 char *str;
586 if (asprintf (&str, "%lx: %s",
587 (unsigned long) (s - fp->ctf_str[CTF_STRTAB_0].cts_strs),
588 s) < 0)
589 return (ctf_set_errno (fp, errno));
590 ctf_dump_append (state, str);
591 s += strlen (s) + 1;
594 return 0;
597 /* Dump a particular section of a CTF file, in textual form. Call with a
598 pointer to a NULL STATE: each call emits a dynamically allocated string
599 containing a description of one entity in the specified section, in order.
600 Only the first call (with a NULL state) may vary SECT. Once the CTF section
601 has been entirely dumped, the call returns NULL and frees and annuls the
602 STATE, ready for another section to be dumped. The returned textual content
603 may span multiple lines: between each call the FUNC is called with one
604 textual line at a time, and should return a suitably decorated line (it can
605 allocate a new one and return it if it likes). */
607 char *
608 ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
609 ctf_dump_decorate_f *func, void *arg)
611 char *str;
612 char *line;
613 ctf_dump_state_t *state = NULL;
615 if (*statep == NULL)
617 /* Data collection. Transforming a call-at-a-time iterator into a
618 return-at-a-time iterator in a language without call/cc is annoying. It
619 is easiest to simply collect everything at once and then return it bit
620 by bit. The first call will take (much) longer than otherwise, but the
621 amortized time needed is the same. */
623 if ((*statep = malloc (sizeof (struct ctf_dump_state))) == NULL)
625 ctf_set_errno (fp, ENOMEM);
626 goto end;
628 state = *statep;
630 memset (state, 0, sizeof (struct ctf_dump_state));
631 state->cds_fp = fp;
632 state->cds_sect = sect;
634 switch (sect)
636 case CTF_SECT_HEADER:
637 ctf_dump_header (fp, state);
638 break;
639 case CTF_SECT_LABEL:
640 if (ctf_label_iter (fp, ctf_dump_label, state) < 0)
642 if (ctf_errno (fp) != ECTF_NOLABELDATA)
643 goto end; /* errno is set for us. */
644 ctf_set_errno (fp, 0);
646 break;
647 case CTF_SECT_OBJT:
648 if (ctf_dump_objts (fp, state, 0) < 0)
649 goto end; /* errno is set for us. */
650 break;
651 case CTF_SECT_FUNC:
652 if (ctf_dump_objts (fp, state, 1) < 0)
653 goto end; /* errno is set for us. */
654 break;
655 case CTF_SECT_VAR:
656 if (ctf_variable_iter (fp, ctf_dump_var, state) < 0)
657 goto end; /* errno is set for us. */
658 break;
659 case CTF_SECT_TYPE:
660 if (ctf_type_iter_all (fp, ctf_dump_type, state) < 0)
661 goto end; /* errno is set for us. */
662 break;
663 case CTF_SECT_STR:
664 ctf_dump_str (fp, state);
665 break;
666 default:
667 ctf_set_errno (fp, ECTF_DUMPSECTUNKNOWN);
668 goto end;
671 else
673 state = *statep;
675 if (state->cds_sect != sect)
677 ctf_set_errno (fp, ECTF_DUMPSECTCHANGED);
678 goto end;
682 if (state->cds_current == NULL)
683 state->cds_current = ctf_list_next (&state->cds_items);
684 else
685 state->cds_current = ctf_list_next (state->cds_current);
687 if (state->cds_current == NULL)
688 goto end;
690 /* Hookery. There is some extra complexity to preserve linefeeds within each
691 item while removing linefeeds at the end. */
692 if (func)
694 size_t len;
696 str = NULL;
697 for (line = state->cds_current->cdi_item; line && *line; )
699 char *nline = line;
700 char *ret;
702 nline = strchr (line, '\n');
703 if (nline)
704 nline[0] = '\0';
706 ret = func (sect, line, arg);
707 str = str_append (str, ret);
708 str = str_append (str, "\n");
709 if (ret != line)
710 free (ret);
712 if (nline)
714 nline[0] = '\n';
715 nline++;
718 line = nline;
721 len = strlen (str);
723 if (str[len-1] == '\n')
724 str[len-1] = '\0';
726 else
728 str = strdup (state->cds_current->cdi_item);
729 if (!str)
731 ctf_set_errno (fp, ENOMEM);
732 return str;
736 ctf_set_errno (fp, 0);
737 return str;
739 end:
740 ctf_dump_free (state);
741 free (state);
742 ctf_set_errno (fp, 0);
743 *statep = NULL;
744 return NULL;