]> Git Repo - binutils.git/blob - libctf/ctf-dump.c
libctf, serialize: functions with no args have a NULL dtd_vlen
[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       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.  */
250 static int
251 ctf_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.  */
268 static int
269 ctf_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.  */
288 static int
289 ctf_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
406 static int
407 ctf_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
433 static int
434 ctf_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.  */
482 static int
483 ctf_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.  */
507 static int
508 ctf_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
549 static int
550 type_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.  */
562 static int
563 ctf_dump_type (ctf_id_t id, int flag, void *arg)
564 {
565   char *str;
566   char *indent;
567   int err = 0;
568   ctf_dump_state_t *state = arg;
569   ctf_dump_membstate_t membstate = { &str, state->cds_fp, NULL };
570
571   /* Indent neatly.  */
572   if (asprintf (&indent, "    %*s", type_hex_digits (id), "") < 0)
573     return (ctf_set_errno (state->cds_fp, ENOMEM));
574
575   /* Dump the type itself.  */
576   if ((str = ctf_dump_format_type (state->cds_fp, id,
577                                    flag | CTF_FT_REFS)) == NULL)
578     goto err;
579   str = str_append (str, "\n");
580
581   membstate.cdm_toplevel_indent = indent;
582
583   /* Member dumping for structs, unions...  */
584   if (ctf_type_kind (state->cds_fp, id) == CTF_K_STRUCT
585       || ctf_type_kind (state->cds_fp, id) == CTF_K_UNION)
586     {
587       if ((ctf_type_visit (state->cds_fp, id, ctf_dump_member, &membstate)) < 0)
588         {
589           if (id == 0 || ctf_errno (state->cds_fp) == ECTF_NONREPRESENTABLE)
590             {
591               ctf_dump_append (state, str);
592               return 0;
593             }
594           ctf_err_warn (state->cds_fp, 1, ctf_errno (state->cds_fp),
595                         _("cannot visit members dumping type 0x%lx"), id);
596           goto err;
597         }
598     }
599
600   /* ... and enums, for which we dump the first and last few members and skip
601      the ones in the middle.  */
602   if (ctf_type_kind (state->cds_fp, id) == CTF_K_ENUM)
603     {
604       int enum_count = ctf_member_count (state->cds_fp, id);
605       ctf_next_t *it = NULL;
606       int i = 0;
607       const char *enumerand;
608       char *bit;
609       int value;
610
611       while ((enumerand = ctf_enum_next (state->cds_fp, id,
612                                          &it, &value)) != NULL)
613         {
614           i++;
615           if ((i > 5) && (i < enum_count - 4))
616             continue;
617
618           str = str_append (str, indent);
619
620           if (asprintf (&bit, "%s: %i\n", enumerand, value) < 0)
621             {
622               err = ENOMEM;
623               ctf_next_destroy (it);
624               goto err;
625             }
626           str = str_append (str, bit);
627           free (bit);
628
629           if ((i == 5) && (enum_count > 10))
630             {
631               str = str_append (str, indent);
632               str = str_append (str, "...\n");
633             }
634         }
635       if (ctf_errno (state->cds_fp) != ECTF_NEXT_END)
636         {
637           ctf_err_warn (state->cds_fp, 1, ctf_errno (state->cds_fp),
638                         _("cannot visit enumerands dumping type 0x%lx"), id);
639           goto err;
640         }
641     }
642
643   ctf_dump_append (state, str);
644   free (indent);
645
646   return 0;
647
648  err:
649   free (indent);
650   free (str);
651   return ctf_set_errno (state->cds_fp, err);
652 }
653
654 /* Dump the string table into the cds_items.  */
655
656 static int
657 ctf_dump_str (ctf_dict_t *fp, ctf_dump_state_t *state)
658 {
659   const char *s = fp->ctf_str[CTF_STRTAB_0].cts_strs;
660
661   for (; s < fp->ctf_str[CTF_STRTAB_0].cts_strs +
662          fp->ctf_str[CTF_STRTAB_0].cts_len;)
663     {
664       char *str;
665       if (asprintf (&str, "0x%lx: %s",
666                     (unsigned long) (s - fp->ctf_str[CTF_STRTAB_0].cts_strs),
667                     s) < 0)
668         return (ctf_set_errno (fp, errno));
669       ctf_dump_append (state, str);
670       s += strlen (s) + 1;
671     }
672
673   return 0;
674 }
675
676 /* Dump a particular section of a CTF file, in textual form.  Call with a
677    pointer to a NULL STATE: each call emits a dynamically allocated string
678    containing a description of one entity in the specified section, in order.
679    Only the first call (with a NULL state) may vary SECT.  Once the CTF section
680    has been entirely dumped, the call returns NULL and frees and annuls the
681    STATE, ready for another section to be dumped.  The returned textual content
682    may span multiple lines: between each call the FUNC is called with one
683    textual line at a time, and should return a suitably decorated line (it can
684    allocate a new one and return it if it likes).  */
685
686 char *
687 ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
688           ctf_dump_decorate_f *func, void *arg)
689 {
690   char *str;
691   char *line;
692   ctf_dump_state_t *state = NULL;
693
694   if (*statep == NULL)
695     {
696       /* Data collection.  Transforming a call-at-a-time iterator into a
697          return-at-a-time iterator in a language without call/cc is annoying. It
698          is easiest to simply collect everything at once and then return it bit
699          by bit.  The first call will take (much) longer than otherwise, but the
700          amortized time needed is the same.  */
701
702       if ((*statep = malloc (sizeof (struct ctf_dump_state))) == NULL)
703         {
704           ctf_set_errno (fp, ENOMEM);
705           goto end;
706         }
707       state = *statep;
708
709       memset (state, 0, sizeof (struct ctf_dump_state));
710       state->cds_fp = fp;
711       state->cds_sect = sect;
712
713       switch (sect)
714         {
715         case CTF_SECT_HEADER:
716           ctf_dump_header (fp, state);
717           break;
718         case CTF_SECT_LABEL:
719           if (ctf_label_iter (fp, ctf_dump_label, state) < 0)
720             {
721               if (ctf_errno (fp) != ECTF_NOLABELDATA)
722                 goto end;               /* errno is set for us.  */
723               ctf_set_errno (fp, 0);
724             }
725           break;
726         case CTF_SECT_OBJT:
727           if (ctf_dump_objts (fp, state, 0) < 0)
728             goto end;                   /* errno is set for us.  */
729           break;
730         case CTF_SECT_FUNC:
731           if (ctf_dump_objts (fp, state, 1) < 0)
732             goto end;                   /* errno is set for us.  */
733           break;
734         case CTF_SECT_VAR:
735           if (ctf_variable_iter (fp, ctf_dump_var, state) < 0)
736             goto end;                   /* errno is set for us.  */
737           break;
738         case CTF_SECT_TYPE:
739           if (ctf_type_iter_all (fp, ctf_dump_type, state) < 0)
740             goto end;                   /* errno is set for us.  */
741           break;
742         case CTF_SECT_STR:
743           ctf_dump_str (fp, state);
744           break;
745         default:
746           ctf_set_errno (fp, ECTF_DUMPSECTUNKNOWN);
747           goto end;
748         }
749     }
750   else
751     {
752       state = *statep;
753
754       if (state->cds_sect != sect)
755         {
756           ctf_set_errno (fp, ECTF_DUMPSECTCHANGED);
757           goto end;
758         }
759     }
760
761   if (state->cds_current == NULL)
762     state->cds_current = ctf_list_next (&state->cds_items);
763   else
764     state->cds_current = ctf_list_next (state->cds_current);
765
766   if (state->cds_current == NULL)
767     goto end;
768
769   /* Hookery.  There is some extra complexity to preserve linefeeds within each
770      item while removing linefeeds at the end.  */
771   if (func)
772     {
773       size_t len;
774
775       str = NULL;
776       for (line = state->cds_current->cdi_item; line && *line; )
777         {
778           char *nline = line;
779           char *ret;
780
781           nline = strchr (line, '\n');
782           if (nline)
783             nline[0] = '\0';
784
785           ret = func (sect, line, arg);
786           str = str_append (str, ret);
787           str = str_append (str, "\n");
788           if (ret != line)
789             free (ret);
790
791           if (nline)
792             {
793               nline[0] = '\n';
794               nline++;
795             }
796
797           line = nline;
798         }
799
800       len = strlen (str);
801
802       if (str[len-1] == '\n')
803         str[len-1] = '\0';
804     }
805   else
806     {
807       str = strdup (state->cds_current->cdi_item);
808       if (!str)
809         {
810           ctf_set_errno (fp, ENOMEM);
811           return str;
812         }
813     }
814
815   ctf_set_errno (fp, 0);
816   return str;
817
818  end:
819   ctf_dump_free (state);
820   free (state);
821   ctf_set_errno (fp, 0);
822   *statep = NULL;
823   return NULL;
824 }
This page took 0.071765 seconds and 4 git commands to generate.