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