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