libctf: fix isspace casts
[deliverable/binutils-gdb.git] / libctf / ctf-dump.c
CommitLineData
a30b3e18 1/* Textual dumping of CTF data.
b3adc24a 2 Copyright (C) 2019-2020 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;
39 ctf_file_t *cds_fp;
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;
49 ctf_file_t *cdm_fp;
50} ctf_dump_membstate_t;
51
52static int
53ctf_dump_append (ctf_dump_state_t *state, char *str)
54{
55 ctf_dump_item_t *cdi;
56
de07e349 57 if ((cdi = malloc (sizeof (struct ctf_dump_item))) == NULL)
a30b3e18
NA
58 return (ctf_set_errno (state->cds_fp, ENOMEM));
59
60 cdi->cdi_item = str;
61 ctf_list_append (&state->cds_items, cdi);
62 return 0;
63}
64
65static void
66ctf_dump_free (ctf_dump_state_t *state)
67{
68 ctf_dump_item_t *cdi, *next_cdi;
69
70 if (state == NULL)
71 return;
72
73 for (cdi = ctf_list_next (&state->cds_items); cdi != NULL;
74 cdi = next_cdi)
75 {
76 free (cdi->cdi_item);
77 next_cdi = ctf_list_next (cdi);
de07e349 78 free (cdi);
a30b3e18
NA
79 }
80}
81
a30b3e18
NA
82/* Return a dump for a single type, without member info: but do show the
83 type's references. */
84
85static char *
b4f0e09c 86ctf_dump_format_type (ctf_file_t *fp, ctf_id_t id, int flag)
a30b3e18
NA
87{
88 ctf_id_t new_id;
89 char *str = NULL, *bit = NULL, *buf = NULL;
90
91 new_id = id;
92 do
93 {
94 ctf_encoding_t enc;
b4f0e09c
NA
95 const char *nonroot_leader = "";
96 const char *nonroot_trailer = "";
a30b3e18
NA
97
98 id = new_id;
b4f0e09c
NA
99 if (flag == CTF_ADD_NONROOT)
100 {
101 nonroot_leader = "{";
102 nonroot_trailer = "}";
103 }
104
a30b3e18
NA
105 buf = ctf_type_aname (fp, id);
106 if (!buf)
791915db
NA
107 {
108 if (id == 0 || ctf_errno (fp) == ECTF_NONREPRESENTABLE)
109 {
9323dd86 110 str = str_append (str, " (type not represented in CTF)");
791915db
NA
111 ctf_set_errno (fp, ECTF_NOTREF);
112 break;
113 }
114
115 goto err;
116 }
a30b3e18 117
70447401
NA
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;
a30b3e18 123
70447401
NA
124 if (buf[0] != '\0')
125 {
126 str = str_append (str, buf);
127 str = str_append (str, " ");
128 }
129
130 free (buf);
131 buf = NULL;
132
133 /* Slices get a different print representation. */
134 if (ctf_type_kind_unsliced (fp, id) == CTF_K_SLICE)
a30b3e18
NA
135 {
136 ctf_type_encoding (fp, id, &enc);
70447401
NA
137 if (asprintf (&bit, "[slice 0x%x:0x%x] ",
138 enc.cte_offset, enc.cte_bits) < 0)
a30b3e18
NA
139 goto oom;
140 }
70447401 141 else if (ctf_type_kind (fp, id) == CTF_K_INTEGER)
a30b3e18 142 {
70447401
NA
143 ctf_type_encoding (fp, id, &enc);
144 if (asprintf (&bit, "[0x%x:0x%x] ",
145 enc.cte_offset, enc.cte_bits) < 0)
a30b3e18
NA
146 goto oom;
147 }
70447401
NA
148 str = str_append (str, bit);
149 free (bit);
150 bit = NULL;
151
152 if (asprintf (&bit, "(size 0x%lx)%s",
153 (unsigned long) ctf_type_size (fp, id),
154 nonroot_trailer) < 0)
155 goto oom;
156
9323dd86 157 str = str_append (str, bit);
a30b3e18
NA
158 free (bit);
159 bit = NULL;
160
161 new_id = ctf_type_reference (fp, id);
162 if (new_id != CTF_ERR)
9323dd86 163 str = str_append (str, " ->");
a30b3e18
NA
164 } while (new_id != CTF_ERR);
165
166 if (ctf_errno (fp) != ECTF_NOTREF)
167 {
168 free (str);
169 return NULL;
170 }
171
172 return str;
173
174 oom:
791915db
NA
175 ctf_set_errno (fp, errno);
176 err:
8e795b46
NA
177 ctf_err_warn (fp, 1, "Cannot format name dumping type 0x%lx: %s", id,
178 ctf_errmsg (ctf_errno (fp)));
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
187ctf_dump_header_strfield (ctf_file_t *fp, ctf_dump_state_t *state,
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
205ctf_dump_header_sectfield (ctf_file_t *fp, ctf_dump_state_t *state,
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
225ctf_dump_header (ctf_file_t *fp, ctf_dump_state_t *state)
226{
227 char *str;
228 const ctf_header_t *hp = fp->ctf_header;
229 const char *vertab[] =
230 {
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
236 };
237 const char *verstr = NULL;
238
239 if (asprintf (&str, "Magic number: %x\n", hp->cth_magic) < 0)
240 goto err;
241 ctf_dump_append (state, str);
242
243 if (hp->cth_version <= CTF_VERSION)
244 verstr = vertab[hp->cth_version];
245
246 if (verstr == NULL)
247 verstr = "(not a valid version)";
248
249 if (asprintf (&str, "Version: %i (%s)\n", hp->cth_version,
250 verstr) < 0)
251 goto err;
252 ctf_dump_append (state, str);
253
254 /* Everything else is only printed if present. */
255
256 /* The flags are unusual in that they represent the ctf_file_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. */
260
261 if (fp->ctf_openflags > 0)
262 {
263 if (fp->ctf_openflags)
264 if (asprintf (&str, "Flags: 0x%x (%s)", fp->ctf_openflags,
265 fp->ctf_openflags & CTF_F_COMPRESS ? "CTF_F_COMPRESS"
266 : "") < 0)
267 goto err;
268 ctf_dump_append (state, str);
269 }
270
271 if (ctf_dump_header_strfield (fp, state, "Parent label",
272 hp->cth_parlabel) < 0)
273 goto err;
274
275 if (ctf_dump_header_strfield (fp, state, "Parent name", hp->cth_parname) < 0)
276 goto err;
277
278 if (ctf_dump_header_strfield (fp, state, "Compilation unit name",
279 hp->cth_cuname) < 0)
280 goto err;
281
282 if (ctf_dump_header_sectfield (fp, state, "Label section", hp->cth_lbloff,
283 hp->cth_objtoff) < 0)
284 goto err;
285
286 if (ctf_dump_header_sectfield (fp, state, "Data object section",
287 hp->cth_objtoff, hp->cth_funcoff) < 0)
288 goto err;
289
290 if (ctf_dump_header_sectfield (fp, state, "Function info section",
291 hp->cth_funcoff, hp->cth_varoff) < 0)
292 goto err;
293
294 if (ctf_dump_header_sectfield (fp, state, "Variable section",
295 hp->cth_varoff, hp->cth_typeoff) < 0)
296 goto err;
297
298 if (ctf_dump_header_sectfield (fp, state, "Type section",
299 hp->cth_typeoff, hp->cth_stroff) < 0)
300 goto err;
301
302 if (ctf_dump_header_sectfield (fp, state, "String section", hp->cth_stroff,
303 hp->cth_stroff + hp->cth_strlen + 1) < 0)
304 goto err;
305
306 return 0;
307 err:
791915db 308 return (ctf_set_errno (fp, errno));
9b32cba4
NA
309}
310
a30b3e18
NA
311/* Dump a single label into the cds_items. */
312
313static int
314ctf_dump_label (const char *name, const ctf_lblinfo_t *info,
315 void *arg)
316{
317 char *str;
318 char *typestr;
319 ctf_dump_state_t *state = arg;
320
321 if (asprintf (&str, "%s -> ", name) < 0)
791915db 322 return (ctf_set_errno (state->cds_fp, errno));
a30b3e18 323
b4f0e09c
NA
324 if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type,
325 CTF_ADD_ROOT)) == NULL)
a30b3e18
NA
326 {
327 free (str);
8e795b46 328 return 0; /* Swallow the error. */
a30b3e18
NA
329 }
330
9323dd86 331 str = str_append (str, typestr);
a30b3e18
NA
332 free (typestr);
333
334 ctf_dump_append (state, str);
335 return 0;
336}
337
338/* Dump all the object entries into the cds_items. (There is no iterator for
339 this section, so we just do it in a loop, and this function handles all of
340 them, rather than only one. */
341
342static int
343ctf_dump_objts (ctf_file_t *fp, ctf_dump_state_t *state)
344{
345 size_t i;
346
347 for (i = 0; i < fp->ctf_nsyms; i++)
348 {
349 char *str;
350 char *typestr;
351 const char *sym_name;
352 ctf_id_t type;
353
a0486bac 354 if ((type = ctf_lookup_by_symbol (state->cds_fp, i)) == CTF_ERR)
a30b3e18
NA
355 switch (ctf_errno (state->cds_fp))
356 {
357 /* Most errors are just an indication that this symbol is not a data
358 symbol, but this one indicates that we were called wrong, on a
359 CTF file with no associated symbol table. */
360 case ECTF_NOSYMTAB:
a0486bac 361 return -1;
a30b3e18
NA
362 case ECTF_NOTDATA:
363 case ECTF_NOTYPEDAT:
364 continue;
365 }
366
367 /* Variable name. */
368 sym_name = ctf_lookup_symbol_name (fp, i);
369 if (sym_name[0] == '\0')
370 {
595a4d43 371 if (asprintf (&str, "%lx -> ", (unsigned long) i) < 0)
791915db 372 return (ctf_set_errno (fp, errno));
a30b3e18
NA
373 }
374 else
375 {
595a4d43 376 if (asprintf (&str, "%s (%lx) -> ", sym_name, (unsigned long) i) < 0)
791915db 377 return (ctf_set_errno (fp, errno));
a30b3e18
NA
378 }
379
380 /* Variable type. */
b4f0e09c
NA
381 if ((typestr = ctf_dump_format_type (state->cds_fp, type,
382 CTF_ADD_ROOT)) == NULL)
a30b3e18
NA
383 {
384 free (str);
8e795b46 385 return 0; /* Swallow the error. */
a30b3e18
NA
386 }
387
9323dd86 388 str = str_append (str, typestr);
a30b3e18
NA
389 free (typestr);
390
391 ctf_dump_append (state, str);
392 }
393 return 0;
394}
395
396/* Dump all the function entries into the cds_items. (As above, there is no
397 iterator for this section.) */
398
399static int
400ctf_dump_funcs (ctf_file_t *fp, ctf_dump_state_t *state)
401{
402 size_t i;
403
404 for (i = 0; i < fp->ctf_nsyms; i++)
405 {
791915db 406 char *str;
c6e9a1e5 407 char *bit = NULL;
791915db 408 const char *err;
a30b3e18
NA
409 const char *sym_name;
410 ctf_funcinfo_t fi;
411 ctf_id_t type;
a30b3e18 412
a0486bac 413 if ((type = ctf_func_info (state->cds_fp, i, &fi)) == CTF_ERR)
a30b3e18
NA
414 switch (ctf_errno (state->cds_fp))
415 {
416 /* Most errors are just an indication that this symbol is not a data
417 symbol, but this one indicates that we were called wrong, on a
418 CTF file with no associated symbol table. */
419 case ECTF_NOSYMTAB:
a0486bac 420 return -1;
a30b3e18 421 case ECTF_NOTDATA:
d18f9f16
NA
422 case ECTF_NOTFUNC:
423 case ECTF_NOFUNCDAT:
a30b3e18
NA
424 continue;
425 }
a30b3e18 426
c6e9a1e5
NA
427 /* Return type and all args. */
428 if ((bit = ctf_type_aname (state->cds_fp, type)) == NULL)
791915db
NA
429 {
430 err = "look up return type";
431 goto err;
432 }
a30b3e18 433
c6e9a1e5 434 /* Replace in the returned string, dropping in the function name. */
a30b3e18
NA
435
436 sym_name = ctf_lookup_symbol_name (fp, i);
c6e9a1e5 437 if (sym_name[0] != '\0')
a30b3e18 438 {
c6e9a1e5
NA
439 char *retstar;
440 char *new_bit;
441 char *walk;
442
443 new_bit = malloc (strlen (bit) + 1 + strlen (sym_name));
444 if (!new_bit)
a30b3e18 445 goto oom;
a30b3e18 446
c6e9a1e5
NA
447 /* See ctf_type_aname. */
448 retstar = strstr (bit, "(*) (");
449 if (!ctf_assert (fp, retstar))
450 goto assert_err;
451 retstar += 2; /* After the '*' */
a30b3e18 452
c6e9a1e5
NA
453 /* C is not good at search-and-replace. */
454 walk = new_bit;
455 memcpy (walk, bit, retstar - bit);
456 walk += (retstar - bit);
457 strcpy (walk, sym_name);
458 walk += strlen (sym_name);
459 strcpy (walk, retstar);
a30b3e18 460
a30b3e18 461 free (bit);
c6e9a1e5 462 bit = new_bit;
a30b3e18
NA
463 }
464
c6e9a1e5
NA
465 if (asprintf (&str, "Symbol 0x%lx: %s", (unsigned long) i, bit) < 0)
466 goto oom;
467 free (bit);
a30b3e18 468
a30b3e18
NA
469 ctf_dump_append (state, str);
470 continue;
471
c6e9a1e5
NA
472 err:
473 ctf_err_warn (fp, 1, "Cannot %s dumping function type for "
474 "symbol 0x%li: %s", err, (unsigned long) i,
475 ctf_errmsg (ctf_errno (state->cds_fp)));
476 free (bit);
477 return -1; /* errno is set for us. */
478
a30b3e18 479 oom:
c6e9a1e5 480 free (bit);
791915db 481 return (ctf_set_errno (fp, errno));
c6e9a1e5
NA
482
483 assert_err:
484 free (bit);
a0486bac 485 return -1; /* errno is set for us. */
a30b3e18
NA
486 }
487 return 0;
488}
489
490/* Dump a single variable into the cds_items. */
491static int
492ctf_dump_var (const char *name, ctf_id_t type, void *arg)
493{
494 char *str;
495 char *typestr;
496 ctf_dump_state_t *state = arg;
497
498 if (asprintf (&str, "%s -> ", name) < 0)
791915db 499 return (ctf_set_errno (state->cds_fp, errno));
a30b3e18 500
b4f0e09c
NA
501 if ((typestr = ctf_dump_format_type (state->cds_fp, type,
502 CTF_ADD_ROOT)) == NULL)
a30b3e18
NA
503 {
504 free (str);
8e795b46 505 return 0; /* Swallow the error. */
a30b3e18
NA
506 }
507
9323dd86 508 str = str_append (str, typestr);
a30b3e18
NA
509 free (typestr);
510
511 ctf_dump_append (state, str);
512 return 0;
513}
514
515/* Dump a single member into the string in the membstate. */
516static int
517ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
518 int depth, void *arg)
519{
520 ctf_dump_membstate_t *state = arg;
521 char *typestr = NULL;
522 char *bit = NULL;
523 ctf_encoding_t ep;
70447401 524 int has_encoding = 0;
a30b3e18
NA
525 ssize_t i;
526
527 for (i = 0; i < depth; i++)
9323dd86 528 *state->cdm_str = str_append (*state->cdm_str, " ");
a30b3e18
NA
529
530 if ((typestr = ctf_type_aname (state->cdm_fp, id)) == NULL)
791915db
NA
531 {
532 if (id == 0 || ctf_errno (state->cdm_fp) == ECTF_NONREPRESENTABLE)
533 {
534 if (asprintf (&bit, " [0x%lx] (type not represented in CTF)",
535 offset) < 0)
536 goto oom;
537
9323dd86 538 *state->cdm_str = str_append (*state->cdm_str, bit);
791915db
NA
539 free (typestr);
540 free (bit);
541 return 0;
542 }
543
70447401
NA
544 return -1; /* errno is set for us. */
545 }
546
547 if (ctf_type_encoding (state->cdm_fp, id, &ep) == 0)
548 {
549 has_encoding = 1;
550 ctf_type_encoding (state->cdm_fp, id, &ep);
551
552 if (asprintf (&bit, " [0x%lx] (ID 0x%lx) (kind %i) %s%s%s:%i "
553 "(aligned at 0x%lx", offset, id,
554 ctf_type_kind (state->cdm_fp, id), typestr,
555 (name[0] != 0 && typestr[0] != 0) ? " " : "", name,
556 ep.cte_bits, (unsigned long) ctf_type_align (state->cdm_fp,
557 id)) < 0)
558 goto oom;
559 }
560 else
561 {
562 if (asprintf (&bit, " [0x%lx] (ID 0x%lx) (kind %i) %s%s%s "
563 "(aligned at 0x%lx", offset, id,
564 ctf_type_kind (state->cdm_fp, id), typestr,
565 (name[0] != 0 && typestr[0] != 0) ? " " : "", name,
566 (unsigned long) ctf_type_align (state->cdm_fp, id)) < 0)
567 goto oom;
791915db 568 }
a30b3e18 569
9323dd86 570 *state->cdm_str = str_append (*state->cdm_str, bit);
a30b3e18
NA
571 free (typestr);
572 free (bit);
573 typestr = NULL;
574 bit = NULL;
575
70447401 576 if (has_encoding)
a30b3e18 577 {
a30b3e18
NA
578 if (asprintf (&bit, ", format 0x%x, offset:bits 0x%x:0x%x", ep.cte_format,
579 ep.cte_offset, ep.cte_bits) < 0)
580 goto oom;
9323dd86 581 *state->cdm_str = str_append (*state->cdm_str, bit);
a30b3e18
NA
582 free (bit);
583 bit = NULL;
584 }
585
9323dd86 586 *state->cdm_str = str_append (*state->cdm_str, ")\n");
a30b3e18
NA
587 return 0;
588
589 oom:
590 free (typestr);
591 free (bit);
791915db 592 return (ctf_set_errno (state->cdm_fp, errno));
a30b3e18
NA
593}
594
595/* Dump a single type into the cds_items. */
a30b3e18 596static int
b4f0e09c 597ctf_dump_type (ctf_id_t id, int flag, void *arg)
a30b3e18
NA
598{
599 char *str;
791915db 600 const char *err;
a30b3e18
NA
601 ctf_dump_state_t *state = arg;
602 ctf_dump_membstate_t membstate = { &str, state->cds_fp };
603 size_t len;
604
b4f0e09c 605 if ((str = ctf_dump_format_type (state->cds_fp, id, flag)) == NULL)
8e795b46 606 goto err_nomsg; /* Error already logged for us. */
a30b3e18 607
9323dd86 608 str = str_append (str, "\n");
a30b3e18 609 if ((ctf_type_visit (state->cds_fp, id, ctf_dump_member, &membstate)) < 0)
791915db
NA
610 {
611 if (id == 0 || ctf_errno (state->cds_fp) == ECTF_NONREPRESENTABLE)
612 {
613 ctf_dump_append (state, str);
614 return 0;
615 }
616 err = "visit members";
617 goto err;
618 }
a30b3e18
NA
619
620 /* Trim off the last linefeed added by ctf_dump_member(). */
621 len = strlen (str);
622 if (str[len-1] == '\n')
623 str[len-1] = '\0';
624
625 ctf_dump_append (state, str);
626 return 0;
627
628 err:
8e795b46
NA
629 ctf_err_warn (state->cds_fp, 1, "Cannot %s dumping type 0x%lx: %s",
630 err, id, ctf_errmsg (ctf_errno (state->cds_fp)));
631 err_nomsg:
a30b3e18 632 free (str);
8e795b46 633 return 0; /* Swallow the error. */
a30b3e18
NA
634}
635
636/* Dump the string table into the cds_items. */
637
638static int
639ctf_dump_str (ctf_file_t *fp, ctf_dump_state_t *state)
640{
641 const char *s = fp->ctf_str[CTF_STRTAB_0].cts_strs;
642
643 for (; s < fp->ctf_str[CTF_STRTAB_0].cts_strs +
644 fp->ctf_str[CTF_STRTAB_0].cts_len;)
645 {
646 char *str;
595a4d43
NA
647 if (asprintf (&str, "%lx: %s",
648 (unsigned long) (s - fp->ctf_str[CTF_STRTAB_0].cts_strs),
a30b3e18 649 s) < 0)
791915db 650 return (ctf_set_errno (fp, errno));
a30b3e18
NA
651 ctf_dump_append (state, str);
652 s += strlen (s) + 1;
653 }
654
655 return 0;
656}
657
658/* Dump a particular section of a CTF file, in textual form. Call with a
659 pointer to a NULL STATE: each call emits a dynamically allocated string
660 containing a description of one entity in the specified section, in order.
661 Only the first call (with a NULL state) may vary SECT. Once the CTF section
662 has been entirely dumped, the call returns NULL and frees and annuls the
663 STATE, ready for another section to be dumped. The returned textual content
664 may span multiple lines: between each call the FUNC is called with one
665 textual line at a time, and should return a suitably decorated line (it can
666 allocate a new one and return it if it likes). */
667
668char *
669ctf_dump (ctf_file_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
670 ctf_dump_decorate_f *func, void *arg)
671{
672 char *str;
673 char *line;
674 ctf_dump_state_t *state = NULL;
675
676 if (*statep == NULL)
677 {
678 /* Data collection. Transforming a call-at-a-time iterator into a
679 return-at-a-time iterator in a language without call/cc is annoying. It
680 is easiest to simply collect everything at once and then return it bit
681 by bit. The first call will take (much) longer than otherwise, but the
682 amortized time needed is the same. */
683
de07e349 684 if ((*statep = malloc (sizeof (struct ctf_dump_state))) == NULL)
a30b3e18
NA
685 {
686 ctf_set_errno (fp, ENOMEM);
687 goto end;
688 }
689 state = *statep;
690
691 memset (state, 0, sizeof (struct ctf_dump_state));
692 state->cds_fp = fp;
693 state->cds_sect = sect;
694
695 switch (sect)
696 {
697 case CTF_SECT_HEADER:
9b32cba4 698 ctf_dump_header (fp, state);
a30b3e18
NA
699 break;
700 case CTF_SECT_LABEL:
701 if (ctf_label_iter (fp, ctf_dump_label, state) < 0)
702 {
703 if (ctf_errno (fp) != ECTF_NOLABELDATA)
704 goto end; /* errno is set for us. */
705 ctf_set_errno (fp, 0);
706 }
707 break;
708 case CTF_SECT_OBJT:
709 if (ctf_dump_objts (fp, state) < 0)
710 goto end; /* errno is set for us. */
711 break;
712 case CTF_SECT_FUNC:
713 if (ctf_dump_funcs (fp, state) < 0)
714 goto end; /* errno is set for us. */
715 break;
716 case CTF_SECT_VAR:
717 if (ctf_variable_iter (fp, ctf_dump_var, state) < 0)
718 goto end; /* errno is set for us. */
719 break;
720 case CTF_SECT_TYPE:
b4f0e09c 721 if (ctf_type_iter_all (fp, ctf_dump_type, state) < 0)
a30b3e18
NA
722 goto end; /* errno is set for us. */
723 break;
724 case CTF_SECT_STR:
725 ctf_dump_str (fp, state);
726 break;
727 default:
728 ctf_set_errno (fp, ECTF_DUMPSECTUNKNOWN);
729 goto end;
730 }
731 }
732 else
733 {
734 state = *statep;
735
736 if (state->cds_sect != sect)
737 {
738 ctf_set_errno (fp, ECTF_DUMPSECTCHANGED);
739 goto end;
740 }
741 }
742
743 if (state->cds_current == NULL)
744 state->cds_current = ctf_list_next (&state->cds_items);
745 else
746 state->cds_current = ctf_list_next (state->cds_current);
747
748 if (state->cds_current == NULL)
749 goto end;
750
751 /* Hookery. There is some extra complexity to preserve linefeeds within each
752 item while removing linefeeds at the end. */
753 if (func)
754 {
755 size_t len;
756
757 str = NULL;
758 for (line = state->cds_current->cdi_item; line && *line; )
759 {
760 char *nline = line;
761 char *ret;
762
763 nline = strchr (line, '\n');
764 if (nline)
765 nline[0] = '\0';
766
767 ret = func (sect, line, arg);
9323dd86
NA
768 str = str_append (str, ret);
769 str = str_append (str, "\n");
a30b3e18
NA
770 if (ret != line)
771 free (ret);
772
773 if (nline)
774 {
775 nline[0] = '\n';
776 nline++;
777 }
778
779 line = nline;
780 }
781
782 len = strlen (str);
783
784 if (str[len-1] == '\n')
785 str[len-1] = '\0';
786 }
787 else
9323dd86
NA
788 {
789 str = strdup (state->cds_current->cdi_item);
790 if (!str)
791 {
792 ctf_set_errno (fp, ENOMEM);
793 return str;
794 }
795 }
a30b3e18
NA
796
797 ctf_set_errno (fp, 0);
798 return str;
799
800 end:
801 ctf_dump_free (state);
de07e349 802 free (state);
a30b3e18
NA
803 ctf_set_errno (fp, 0);
804 *statep = NULL;
805 return NULL;
806}
This page took 0.116959 seconds and 4 git commands to generate.