]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - libctf/ctf-dump.c
libctf: support encodings for enums
[thirdparty/binutils-gdb.git] / libctf / ctf-dump.c
CommitLineData
a30b3e18 1/* Textual dumping of CTF data.
250d07de 2 Copyright (C) 2019-2021 Free Software Foundation, Inc.
a30b3e18
NA
3
4 This file is part of libctf.
5
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.
10
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.
15
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/>. */
19
20#include <ctf-impl.h>
21#include <string.h>
22
9323dd86
NA
23#define str_append(s, a) ctf_str_append_noerr (s, a)
24
a30b3e18
NA
25/* One item to be dumped, in string form. */
26
27typedef struct ctf_dump_item
28{
29 ctf_list_t cdi_list;
30 char *cdi_item;
31} ctf_dump_item_t;
32
33/* Cross-call state for dumping. Basically just enough to track the section in
34 use and a list of return strings. */
35
36struct ctf_dump_state
37{
38 ctf_sect_names_t cds_sect;
139633c3 39 ctf_dict_t *cds_fp;
a30b3e18
NA
40 ctf_dump_item_t *cds_current;
41 ctf_list_t cds_items;
42};
43
44/* Cross-call state for ctf_dump_member. */
45
46typedef struct ctf_dump_membstate
47{
48 char **cdm_str;
139633c3 49 ctf_dict_t *cdm_fp;
37002871 50 const char *cdm_toplevel_indent;
a30b3e18
NA
51} ctf_dump_membstate_t;
52
53static int
54ctf_dump_append (ctf_dump_state_t *state, char *str)
55{
56 ctf_dump_item_t *cdi;
57
de07e349 58 if ((cdi = malloc (sizeof (struct ctf_dump_item))) == NULL)
a30b3e18
NA
59 return (ctf_set_errno (state->cds_fp, ENOMEM));
60
61 cdi->cdi_item = str;
62 ctf_list_append (&state->cds_items, cdi);
63 return 0;
64}
65
66static void
67ctf_dump_free (ctf_dump_state_t *state)
68{
69 ctf_dump_item_t *cdi, *next_cdi;
70
71 if (state == NULL)
72 return;
73
74 for (cdi = ctf_list_next (&state->cds_items); cdi != NULL;
75 cdi = next_cdi)
76 {
77 free (cdi->cdi_item);
78 next_cdi = ctf_list_next (cdi);
de07e349 79 free (cdi);
a30b3e18
NA
80 }
81}
82
37002871
NA
83/* Return a dump for a single type, without member info: but do optionally show
84 the type's references. */
85
86#define CTF_FT_REFS 0x2 /* Print referenced types. */
87#define CTF_FT_BITFIELD 0x4 /* Print :BITS if a bitfield. */
88#define CTF_FT_ID 0x8 /* Print "ID: " in front of type IDs. */
a30b3e18
NA
89
90static char *
139633c3 91ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
a30b3e18
NA
92{
93 ctf_id_t new_id;
94 char *str = NULL, *bit = NULL, *buf = NULL;
95
37002871 96 ctf_set_errno (fp, 0);
a30b3e18
NA
97 new_id = id;
98 do
99 {
37002871 100 ctf_encoding_t ep;
91e7ce2f
NA
101 ctf_arinfo_t ar;
102 int kind, unsliced_kind;
b4f0e09c
NA
103 const char *nonroot_leader = "";
104 const char *nonroot_trailer = "";
37002871 105 const char *idstr = "";
a30b3e18
NA
106
107 id = new_id;
b4f0e09c
NA
108 if (flag == CTF_ADD_NONROOT)
109 {
110 nonroot_leader = "{";
111 nonroot_trailer = "}";
112 }
113
a30b3e18
NA
114 buf = ctf_type_aname (fp, id);
115 if (!buf)
791915db
NA
116 {
117 if (id == 0 || ctf_errno (fp) == ECTF_NONREPRESENTABLE)
118 {
37002871 119 ctf_set_errno (fp, ECTF_NONREPRESENTABLE);
9323dd86 120 str = str_append (str, " (type not represented in CTF)");
37002871 121 return str;
791915db
NA
122 }
123
124 goto err;
125 }
a30b3e18 126
37002871
NA
127 if (flag & CTF_FT_ID)
128 idstr = "ID ";
129 if (asprintf (&bit, "%s%s0x%lx: (kind %i) ", nonroot_leader, idstr,
130 id, ctf_type_kind (fp, id)) < 0)
70447401
NA
131 goto oom;
132 str = str_append (str, bit);
133 free (bit);
134 bit = NULL;
a30b3e18 135
70447401 136 if (buf[0] != '\0')
91e7ce2f 137 str = str_append (str, buf);
70447401
NA
138
139 free (buf);
140 buf = NULL;
37002871 141
91e7ce2f
NA
142 unsliced_kind = ctf_type_kind_unsliced (fp, id);
143 kind = ctf_type_kind (fp, id);
70447401 144
69a28486
NA
145 /* Report encodings of everything with an encoding other than enums:
146 base-type enums cannot have a nonzero cte_offset or cte_bits value.
147 (Slices of them can, but they are of kind CTF_K_SLICE.) */
148 if (unsliced_kind != CTF_K_ENUM && ctf_type_encoding (fp, id, &ep) == 0)
37002871 149 {
cf6a0b98 150 if ((ssize_t) ep.cte_bits != ctf_type_size (fp, id) * CHAR_BIT
37002871
NA
151 && flag & CTF_FT_BITFIELD)
152 {
153 if (asprintf (&bit, ":%i", ep.cte_bits) < 0)
154 goto oom;
155 str = str_append (str, bit);
156 free (bit);
157 bit = NULL;
158 }
159
cf6a0b98 160 if ((ssize_t) ep.cte_bits != ctf_type_size (fp, id) * CHAR_BIT
37002871
NA
161 || ep.cte_offset != 0)
162 {
163 const char *slice = "";
164
165 if (unsliced_kind == CTF_K_SLICE)
166 slice = "slice ";
167
168 if (asprintf (&bit, " [%s0x%x:0x%x]",
169 slice, ep.cte_offset, ep.cte_bits) < 0)
170 goto oom;
171 str = str_append (str, bit);
172 free (bit);
173 bit = NULL;
174 }
175
176 if (asprintf (&bit, " (format 0x%x)", ep.cte_format) < 0)
177 goto oom;
178 str = str_append (str, bit);
179 free (bit);
180 bit = NULL;
181 }
182
183 if (kind != CTF_K_FUNCTION && kind != CTF_K_FORWARD)
a30b3e18 184 {
37002871
NA
185 if (asprintf (&bit, " (size 0x%lx)",
186 (unsigned long) ctf_type_size (fp, id)) < 0)
a30b3e18 187 goto oom;
37002871
NA
188
189 str = str_append (str, bit);
190 free (bit);
191 bit = NULL;
a30b3e18 192 }
37002871
NA
193
194 if (kind != CTF_K_FORWARD)
a30b3e18 195 {
37002871
NA
196 if (asprintf (&bit, " (aligned at 0x%lx)",
197 (unsigned long) ctf_type_align (fp, id)) < 0)
a30b3e18 198 goto oom;
37002871
NA
199
200 str = str_append (str, bit);
201 free (bit);
202 bit = NULL;
a30b3e18 203 }
70447401 204
37002871
NA
205 if (nonroot_trailer[0] != 0)
206 str = str_append (str, nonroot_trailer);
70447401 207
37002871
NA
208 /* Just exit after one iteration if we are not showing the types this type
209 references. */
210 if (!(flag & CTF_FT_REFS))
211 return str;
a30b3e18 212
91e7ce2f
NA
213 /* Keep going as long as this type references another. We consider arrays
214 to "reference" their element type. */
215
216 if (kind == CTF_K_ARRAY)
217 {
218 if (ctf_array_info (fp, id, &ar) < 0)
219 goto err;
220 new_id = ar.ctr_contents;
221 }
222 else
223 new_id = ctf_type_reference (fp, id);
a30b3e18 224 if (new_id != CTF_ERR)
37002871 225 str = str_append (str, " -> ");
eefe721e
NA
226 }
227 while (new_id != CTF_ERR);
a30b3e18
NA
228
229 if (ctf_errno (fp) != ECTF_NOTREF)
230 {
231 free (str);
232 return NULL;
233 }
234
235 return str;
236
237 oom:
791915db
NA
238 ctf_set_errno (fp, errno);
239 err:
926c9e76 240 ctf_err_warn (fp, 1, 0, _("cannot format name dumping type 0x%lx"), id);
a30b3e18
NA
241 free (buf);
242 free (str);
243 free (bit);
a30b3e18
NA
244 return NULL;
245}
246
9b32cba4
NA
247/* Dump one string field from the file header into the cds_items. */
248static int
139633c3 249ctf_dump_header_strfield (ctf_dict_t *fp, ctf_dump_state_t *state,
9b32cba4
NA
250 const char *name, uint32_t value)
251{
252 char *str;
253 if (value)
254 {
255 if (asprintf (&str, "%s: %s\n", name, ctf_strptr (fp, value)) < 0)
256 goto err;
257 ctf_dump_append (state, str);
258 }
259 return 0;
260
261 err:
791915db 262 return (ctf_set_errno (fp, errno));
9b32cba4
NA
263}
264
265/* Dump one section-offset field from the file header into the cds_items. */
266static int
139633c3 267ctf_dump_header_sectfield (ctf_dict_t *fp, ctf_dump_state_t *state,
9b32cba4
NA
268 const char *sect, uint32_t off, uint32_t nextoff)
269{
270 char *str;
271 if (nextoff - off)
272 {
273 if (asprintf (&str, "%s:\t0x%lx -- 0x%lx (0x%lx bytes)\n", sect,
274 (unsigned long) off, (unsigned long) (nextoff - 1),
275 (unsigned long) (nextoff - off)) < 0)
276 goto err;
277 ctf_dump_append (state, str);
278 }
279 return 0;
280
281 err:
791915db 282 return (ctf_set_errno (fp, errno));
9b32cba4
NA
283}
284
285/* Dump the file header into the cds_items. */
286static int
139633c3 287ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
9b32cba4
NA
288{
289 char *str;
4665e895 290 char *flagstr = NULL;
9b32cba4
NA
291 const ctf_header_t *hp = fp->ctf_header;
292 const char *vertab[] =
293 {
294 NULL, "CTF_VERSION_1",
295 "CTF_VERSION_1_UPGRADED_3 (latest format, version 1 type "
296 "boundaries)",
297 "CTF_VERSION_2",
298 "CTF_VERSION_3", NULL
299 };
300 const char *verstr = NULL;
301
57f97d0e 302 if (asprintf (&str, "Magic number: 0x%x\n", hp->cth_magic) < 0)
9b32cba4
NA
303 goto err;
304 ctf_dump_append (state, str);
305
306 if (hp->cth_version <= CTF_VERSION)
307 verstr = vertab[hp->cth_version];
308
309 if (verstr == NULL)
310 verstr = "(not a valid version)";
311
312 if (asprintf (&str, "Version: %i (%s)\n", hp->cth_version,
313 verstr) < 0)
314 goto err;
315 ctf_dump_append (state, str);
316
317 /* Everything else is only printed if present. */
318
139633c3 319 /* The flags are unusual in that they represent the ctf_dict_t *in memory*:
9b32cba4
NA
320 flags representing compression, etc, are turned off as the file is
321 decompressed. So we store a copy of the flags before they are changed, for
322 the dumper. */
323
324 if (fp->ctf_openflags > 0)
325 {
4665e895
NA
326 if (asprintf (&flagstr, "%s%s%s%s%s%s%s",
327 fp->ctf_openflags & CTF_F_COMPRESS
328 ? "CTF_F_COMPRESS": "",
329 (fp->ctf_openflags & CTF_F_COMPRESS)
330 && (fp->ctf_openflags & ~CTF_F_COMPRESS)
331 ? ", " : "",
332 fp->ctf_openflags & CTF_F_NEWFUNCINFO
333 ? "CTF_F_NEWFUNCINFO" : "",
334 (fp->ctf_openflags & (CTF_F_COMPRESS | CTF_F_NEWFUNCINFO))
335 && (fp->ctf_openflags & ~(CTF_F_COMPRESS | CTF_F_NEWFUNCINFO))
336 ? ", " : "",
337 fp->ctf_openflags & CTF_F_IDXSORTED
338 ? "CTF_F_IDXSORTED" : "",
339 fp->ctf_openflags & (CTF_F_COMPRESS | CTF_F_NEWFUNCINFO
340 | CTF_F_IDXSORTED)
341 && (fp->ctf_openflags & ~(CTF_F_COMPRESS | CTF_F_NEWFUNCINFO
342 | CTF_F_IDXSORTED))
343 ? ", " : "",
344 fp->ctf_openflags & CTF_F_DYNSTR
345 ? "CTF_F_DYNSTR" : "") < 0)
346 goto err;
347
348 if (asprintf (&str, "Flags: 0x%x (%s)", fp->ctf_openflags, flagstr) < 0)
9b32cba4
NA
349 goto err;
350 ctf_dump_append (state, str);
351 }
352
353 if (ctf_dump_header_strfield (fp, state, "Parent label",
354 hp->cth_parlabel) < 0)
355 goto err;
356
357 if (ctf_dump_header_strfield (fp, state, "Parent name", hp->cth_parname) < 0)
358 goto err;
359
360 if (ctf_dump_header_strfield (fp, state, "Compilation unit name",
361 hp->cth_cuname) < 0)
362 goto err;
363
364 if (ctf_dump_header_sectfield (fp, state, "Label section", hp->cth_lbloff,
365 hp->cth_objtoff) < 0)
366 goto err;
367
368 if (ctf_dump_header_sectfield (fp, state, "Data object section",
369 hp->cth_objtoff, hp->cth_funcoff) < 0)
370 goto err;
371
372 if (ctf_dump_header_sectfield (fp, state, "Function info section",
4665e895
NA
373 hp->cth_funcoff, hp->cth_objtidxoff) < 0)
374 goto err;
375
376 if (ctf_dump_header_sectfield (fp, state, "Object index section",
377 hp->cth_objtidxoff, hp->cth_funcidxoff) < 0)
378 goto err;
379
380 if (ctf_dump_header_sectfield (fp, state, "Function index section",
381 hp->cth_funcidxoff, hp->cth_varoff) < 0)
9b32cba4
NA
382 goto err;
383
384 if (ctf_dump_header_sectfield (fp, state, "Variable section",
385 hp->cth_varoff, hp->cth_typeoff) < 0)
386 goto err;
387
388 if (ctf_dump_header_sectfield (fp, state, "Type section",
389 hp->cth_typeoff, hp->cth_stroff) < 0)
390 goto err;
391
392 if (ctf_dump_header_sectfield (fp, state, "String section", hp->cth_stroff,
393 hp->cth_stroff + hp->cth_strlen + 1) < 0)
394 goto err;
395
396 return 0;
397 err:
4665e895 398 free (flagstr);
791915db 399 return (ctf_set_errno (fp, errno));
9b32cba4
NA
400}
401
a30b3e18
NA
402/* Dump a single label into the cds_items. */
403
404static int
405ctf_dump_label (const char *name, const ctf_lblinfo_t *info,
406 void *arg)
407{
408 char *str;
409 char *typestr;
410 ctf_dump_state_t *state = arg;
411
412 if (asprintf (&str, "%s -> ", name) < 0)
791915db 413 return (ctf_set_errno (state->cds_fp, errno));
a30b3e18 414
b4f0e09c 415 if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type,
37002871 416 CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
a30b3e18
NA
417 {
418 free (str);
8e795b46 419 return 0; /* Swallow the error. */
a30b3e18
NA
420 }
421
9323dd86 422 str = str_append (str, typestr);
a30b3e18
NA
423 free (typestr);
424
425 ctf_dump_append (state, str);
426 return 0;
427}
428
4665e895 429/* Dump all the object or function entries into the cds_items. */
a30b3e18
NA
430
431static int
4665e895 432ctf_dump_objts (ctf_dict_t *fp, ctf_dump_state_t *state, int functions)
a30b3e18 433{
4665e895
NA
434 const char *name;
435 ctf_id_t id;
436 ctf_next_t *i = NULL;
437 char *str = NULL;
438
439 if ((functions && fp->ctf_funcidx_names)
440 || (!functions && fp->ctf_objtidx_names))
441 str = str_append (str, _("Section is indexed.\n"));
442 else if (fp->ctf_symtab.cts_data == NULL)
443 str = str_append (str, _("No symbol table.\n"));
444
445 while ((id = ctf_symbol_next (fp, &i, &name, functions)) != CTF_ERR)
a30b3e18 446 {
4665e895 447 char *typestr = NULL;
a30b3e18 448
91e7ce2f
NA
449 /* Emit the name, if we know it. No trailing space: ctf_dump_format_type
450 has a leading one. */
4665e895 451 if (name)
a30b3e18 452 {
37002871 453 if (asprintf (&str, "%s -> ", name) < 0)
4665e895 454 goto oom;
a30b3e18 455 }
4665e895
NA
456 else
457 str = xstrdup ("");
a30b3e18 458
91e7ce2f 459 if ((typestr = ctf_dump_format_type (state->cds_fp, id,
37002871 460 CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
791915db 461 {
91e7ce2f
NA
462 ctf_dump_append (state, str);
463 continue; /* Swallow the error. */
a30b3e18
NA
464 }
465
4665e895 466 str = str_append (str, typestr);
91e7ce2f 467 free (typestr);
a30b3e18
NA
468 ctf_dump_append (state, str);
469 continue;
470
471 oom:
4665e895
NA
472 ctf_set_errno (fp, ENOMEM);
473 ctf_next_destroy (i);
474 return -1;
a30b3e18
NA
475 }
476 return 0;
477}
478
479/* Dump a single variable into the cds_items. */
480static int
481ctf_dump_var (const char *name, ctf_id_t type, void *arg)
482{
483 char *str;
484 char *typestr;
485 ctf_dump_state_t *state = arg;
486
487 if (asprintf (&str, "%s -> ", name) < 0)
791915db 488 return (ctf_set_errno (state->cds_fp, errno));
a30b3e18 489
b4f0e09c 490 if ((typestr = ctf_dump_format_type (state->cds_fp, type,
37002871 491 CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
a30b3e18
NA
492 {
493 free (str);
8e795b46 494 return 0; /* Swallow the error. */
a30b3e18
NA
495 }
496
9323dd86 497 str = str_append (str, typestr);
a30b3e18
NA
498 free (typestr);
499
500 ctf_dump_append (state, str);
501 return 0;
502}
503
37002871 504/* Dump a single struct/union member into the string in the membstate. */
a30b3e18
NA
505static int
506ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
57f97d0e 507 int depth, void *arg)
a30b3e18
NA
508{
509 ctf_dump_membstate_t *state = arg;
510 char *typestr = NULL;
511 char *bit = NULL;
57f97d0e 512
37002871 513 /* The struct/union itself has already been printed. */
57f97d0e 514 if (depth == 0)
37002871 515 return 0;
57f97d0e 516
37002871 517 if (asprintf (&bit, "%s%*s", state->cdm_toplevel_indent, (depth-1)*4, "") < 0)
57f97d0e
NA
518 goto oom;
519 *state->cdm_str = str_append (*state->cdm_str, bit);
520 free (bit);
a30b3e18 521
37002871
NA
522 if ((typestr = ctf_dump_format_type (state->cdm_fp, id,
523 CTF_ADD_ROOT | CTF_FT_BITFIELD
524 | CTF_FT_ID)) == NULL)
525 return -1; /* errno is set for us. */
791915db 526
37002871
NA
527 if (asprintf (&bit, "[0x%lx] %s: %s\n", offset, name, typestr) < 0)
528 goto oom;
a30b3e18 529
9323dd86 530 *state->cdm_str = str_append (*state->cdm_str, bit);
a30b3e18
NA
531 free (typestr);
532 free (bit);
533 typestr = NULL;
534 bit = NULL;
535
a30b3e18
NA
536 return 0;
537
538 oom:
539 free (typestr);
540 free (bit);
791915db 541 return (ctf_set_errno (state->cdm_fp, errno));
a30b3e18
NA
542}
543
37002871
NA
544/* Report the number of digits in the hexadecimal representation of a type
545 ID. */
546
547static int
548type_hex_digits (ctf_id_t id)
549{
550 int i = 0;
551
552 if (id == 0)
553 return 1;
554
555 for (; id > 0; id >>= 4, i++);
556 return i;
557}
558
a30b3e18 559/* Dump a single type into the cds_items. */
a30b3e18 560static int
b4f0e09c 561ctf_dump_type (ctf_id_t id, int flag, void *arg)
a30b3e18
NA
562{
563 char *str;
37002871
NA
564 char *indent;
565 int err = 0;
a30b3e18 566 ctf_dump_state_t *state = arg;
57f97d0e 567 ctf_dump_membstate_t membstate = { &str, state->cds_fp, NULL };
a30b3e18 568
37002871
NA
569 /* Indent neatly. */
570 if (asprintf (&indent, " %*s", type_hex_digits (id), "") < 0)
571 return (ctf_set_errno (state->cds_fp, ENOMEM));
a30b3e18 572
37002871
NA
573 /* Dump the type itself. */
574 if ((str = ctf_dump_format_type (state->cds_fp, id,
575 flag | CTF_FT_REFS)) == NULL)
576 goto err;
9323dd86 577 str = str_append (str, "\n");
37002871
NA
578
579 membstate.cdm_toplevel_indent = indent;
580
581 /* Member dumping for structs, unions... */
582 if (ctf_type_kind (state->cds_fp, id) == CTF_K_STRUCT
583 || ctf_type_kind (state->cds_fp, id) == CTF_K_UNION)
791915db 584 {
37002871 585 if ((ctf_type_visit (state->cds_fp, id, ctf_dump_member, &membstate)) < 0)
791915db 586 {
37002871
NA
587 if (id == 0 || ctf_errno (state->cds_fp) == ECTF_NONREPRESENTABLE)
588 {
589 ctf_dump_append (state, str);
590 return 0;
591 }
592 ctf_err_warn (state->cds_fp, 1, ctf_errno (state->cds_fp),
593 _("cannot visit members dumping type 0x%lx"), id);
594 goto err;
791915db 595 }
791915db 596 }
a30b3e18 597
37002871
NA
598 /* ... and enums, for which we dump the first and last few members and skip
599 the ones in the middle. */
600 if (ctf_type_kind (state->cds_fp, id) == CTF_K_ENUM)
601 {
602 int enum_count = ctf_member_count (state->cds_fp, id);
603 ctf_next_t *it = NULL;
604 int i = 0;
605 const char *enumerand;
606 char *bit;
607 int value;
608
609 while ((enumerand = ctf_enum_next (state->cds_fp, id,
610 &it, &value)) != NULL)
611 {
612 i++;
613 if ((i > 5) && (i < enum_count - 4))
614 continue;
615
616 str = str_append (str, indent);
617
618 if (asprintf (&bit, "%s: %i\n", enumerand, value) < 0)
619 {
620 err = ENOMEM;
621 ctf_next_destroy (it);
622 goto err;
623 }
624 str = str_append (str, bit);
625 free (bit);
626
627 if ((i == 5) && (enum_count > 10))
628 {
629 str = str_append (str, indent);
630 str = str_append (str, "...\n");
631 }
632 }
633 if (ctf_errno (state->cds_fp) != ECTF_NEXT_END)
634 {
635 ctf_err_warn (state->cds_fp, 1, ctf_errno (state->cds_fp),
636 _("cannot visit enumerands dumping type 0x%lx"), id);
637 goto err;
638 }
639 }
a30b3e18
NA
640
641 ctf_dump_append (state, str);
37002871
NA
642 free (indent);
643
a30b3e18
NA
644 return 0;
645
646 err:
37002871 647 free (indent);
a30b3e18 648 free (str);
37002871 649 return ctf_set_errno (state->cds_fp, err);
a30b3e18
NA
650}
651
652/* Dump the string table into the cds_items. */
653
654static int
139633c3 655ctf_dump_str (ctf_dict_t *fp, ctf_dump_state_t *state)
a30b3e18
NA
656{
657 const char *s = fp->ctf_str[CTF_STRTAB_0].cts_strs;
658
659 for (; s < fp->ctf_str[CTF_STRTAB_0].cts_strs +
660 fp->ctf_str[CTF_STRTAB_0].cts_len;)
661 {
662 char *str;
57f97d0e 663 if (asprintf (&str, "0x%lx: %s",
595a4d43 664 (unsigned long) (s - fp->ctf_str[CTF_STRTAB_0].cts_strs),
a30b3e18 665 s) < 0)
791915db 666 return (ctf_set_errno (fp, errno));
a30b3e18
NA
667 ctf_dump_append (state, str);
668 s += strlen (s) + 1;
669 }
670
671 return 0;
672}
673
674/* Dump a particular section of a CTF file, in textual form. Call with a
675 pointer to a NULL STATE: each call emits a dynamically allocated string
676 containing a description of one entity in the specified section, in order.
677 Only the first call (with a NULL state) may vary SECT. Once the CTF section
678 has been entirely dumped, the call returns NULL and frees and annuls the
679 STATE, ready for another section to be dumped. The returned textual content
680 may span multiple lines: between each call the FUNC is called with one
681 textual line at a time, and should return a suitably decorated line (it can
682 allocate a new one and return it if it likes). */
683
684char *
139633c3 685ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
a30b3e18
NA
686 ctf_dump_decorate_f *func, void *arg)
687{
688 char *str;
689 char *line;
690 ctf_dump_state_t *state = NULL;
691
692 if (*statep == NULL)
693 {
694 /* Data collection. Transforming a call-at-a-time iterator into a
695 return-at-a-time iterator in a language without call/cc is annoying. It
696 is easiest to simply collect everything at once and then return it bit
697 by bit. The first call will take (much) longer than otherwise, but the
698 amortized time needed is the same. */
699
de07e349 700 if ((*statep = malloc (sizeof (struct ctf_dump_state))) == NULL)
a30b3e18
NA
701 {
702 ctf_set_errno (fp, ENOMEM);
703 goto end;
704 }
705 state = *statep;
706
707 memset (state, 0, sizeof (struct ctf_dump_state));
708 state->cds_fp = fp;
709 state->cds_sect = sect;
710
711 switch (sect)
712 {
713 case CTF_SECT_HEADER:
9b32cba4 714 ctf_dump_header (fp, state);
a30b3e18
NA
715 break;
716 case CTF_SECT_LABEL:
717 if (ctf_label_iter (fp, ctf_dump_label, state) < 0)
718 {
719 if (ctf_errno (fp) != ECTF_NOLABELDATA)
720 goto end; /* errno is set for us. */
721 ctf_set_errno (fp, 0);
722 }
723 break;
724 case CTF_SECT_OBJT:
4665e895 725 if (ctf_dump_objts (fp, state, 0) < 0)
a30b3e18
NA
726 goto end; /* errno is set for us. */
727 break;
728 case CTF_SECT_FUNC:
4665e895 729 if (ctf_dump_objts (fp, state, 1) < 0)
a30b3e18
NA
730 goto end; /* errno is set for us. */
731 break;
732 case CTF_SECT_VAR:
733 if (ctf_variable_iter (fp, ctf_dump_var, state) < 0)
734 goto end; /* errno is set for us. */
735 break;
736 case CTF_SECT_TYPE:
b4f0e09c 737 if (ctf_type_iter_all (fp, ctf_dump_type, state) < 0)
a30b3e18
NA
738 goto end; /* errno is set for us. */
739 break;
740 case CTF_SECT_STR:
741 ctf_dump_str (fp, state);
742 break;
743 default:
744 ctf_set_errno (fp, ECTF_DUMPSECTUNKNOWN);
745 goto end;
746 }
747 }
748 else
749 {
750 state = *statep;
751
752 if (state->cds_sect != sect)
753 {
754 ctf_set_errno (fp, ECTF_DUMPSECTCHANGED);
755 goto end;
756 }
757 }
758
759 if (state->cds_current == NULL)
760 state->cds_current = ctf_list_next (&state->cds_items);
761 else
762 state->cds_current = ctf_list_next (state->cds_current);
763
764 if (state->cds_current == NULL)
765 goto end;
766
767 /* Hookery. There is some extra complexity to preserve linefeeds within each
768 item while removing linefeeds at the end. */
769 if (func)
770 {
771 size_t len;
772
773 str = NULL;
774 for (line = state->cds_current->cdi_item; line && *line; )
775 {
776 char *nline = line;
777 char *ret;
778
779 nline = strchr (line, '\n');
780 if (nline)
781 nline[0] = '\0';
782
783 ret = func (sect, line, arg);
9323dd86
NA
784 str = str_append (str, ret);
785 str = str_append (str, "\n");
a30b3e18
NA
786 if (ret != line)
787 free (ret);
788
789 if (nline)
790 {
791 nline[0] = '\n';
792 nline++;
793 }
794
795 line = nline;
796 }
797
798 len = strlen (str);
799
800 if (str[len-1] == '\n')
801 str[len-1] = '\0';
802 }
803 else
9323dd86
NA
804 {
805 str = strdup (state->cds_current->cdi_item);
806 if (!str)
807 {
808 ctf_set_errno (fp, ENOMEM);
809 return str;
810 }
811 }
a30b3e18
NA
812
813 ctf_set_errno (fp, 0);
814 return str;
815
816 end:
817 ctf_dump_free (state);
de07e349 818 free (state);
a30b3e18
NA
819 ctf_set_errno (fp, 0);
820 *statep = NULL;
821 return NULL;
822}