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