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