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