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