libctf: fix a number of build problems found on Solaris and NetBSD
[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 *
98ctf_dump_format_type (ctf_file_t *fp, ctf_id_t id)
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
108 id = new_id;
109 buf = ctf_type_aname (fp, id);
110 if (!buf)
111 goto oom;
112
113 /* Slices get a different print representation. */
114
115 if (ctf_is_slice (fp, id, &enc))
116 {
117 ctf_type_encoding (fp, id, &enc);
118 if (asprintf (&bit, " %lx: [slice 0x%x:0x%x]",
119 id, enc.cte_offset, enc.cte_bits) < 0)
120 goto oom;
121 }
122 else
123 {
124 if (asprintf (&bit, " %lx: %s (size %lx)", id, buf[0] == '\0' ?
125 "(nameless)" : buf, ctf_type_size (fp, id)) < 0)
126 goto oom;
127 }
128 free (buf);
129 buf = NULL;
130 str = ctf_str_append (str, bit);
131 free (bit);
132 bit = NULL;
133
134 new_id = ctf_type_reference (fp, id);
135 if (new_id != CTF_ERR)
136 str = ctf_str_append (str, " ->");
137 } while (new_id != CTF_ERR);
138
139 if (ctf_errno (fp) != ECTF_NOTREF)
140 {
141 free (str);
142 return NULL;
143 }
144
145 return str;
146
147 oom:
148 free (buf);
149 free (str);
150 free (bit);
151 ctf_set_errno (fp, ENOMEM);
152 return NULL;
153}
154
155/* Dump a single label into the cds_items. */
156
157static int
158ctf_dump_label (const char *name, const ctf_lblinfo_t *info,
159 void *arg)
160{
161 char *str;
162 char *typestr;
163 ctf_dump_state_t *state = arg;
164
165 if (asprintf (&str, "%s -> ", name) < 0)
166 return (ctf_set_errno (state->cds_fp, ENOMEM));
167
168 if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type)) == NULL)
169 {
170 free (str);
a0486bac 171 return -1; /* errno is set for us. */
a30b3e18
NA
172 }
173
174 str = ctf_str_append (str, typestr);
175 free (typestr);
176
177 ctf_dump_append (state, str);
178 return 0;
179}
180
181/* Dump all the object entries into the cds_items. (There is no iterator for
182 this section, so we just do it in a loop, and this function handles all of
183 them, rather than only one. */
184
185static int
186ctf_dump_objts (ctf_file_t *fp, ctf_dump_state_t *state)
187{
188 size_t i;
189
190 for (i = 0; i < fp->ctf_nsyms; i++)
191 {
192 char *str;
193 char *typestr;
194 const char *sym_name;
195 ctf_id_t type;
196
a0486bac 197 if ((type = ctf_lookup_by_symbol (state->cds_fp, i)) == CTF_ERR)
a30b3e18
NA
198 switch (ctf_errno (state->cds_fp))
199 {
200 /* Most errors are just an indication that this symbol is not a data
201 symbol, but this one indicates that we were called wrong, on a
202 CTF file with no associated symbol table. */
203 case ECTF_NOSYMTAB:
a0486bac 204 return -1;
a30b3e18
NA
205 case ECTF_NOTDATA:
206 case ECTF_NOTYPEDAT:
207 continue;
208 }
209
210 /* Variable name. */
211 sym_name = ctf_lookup_symbol_name (fp, i);
212 if (sym_name[0] == '\0')
213 {
214 if (asprintf (&str, "%lx -> ", i) < 0)
215 return (ctf_set_errno (fp, ENOMEM));
216 }
217 else
218 {
219 if (asprintf (&str, "%s (%lx) -> ", sym_name, i) < 0)
220 return (ctf_set_errno (fp, ENOMEM));
221 }
222
223 /* Variable type. */
224 if ((typestr = ctf_dump_format_type (state->cds_fp, type)) == NULL)
225 {
226 free (str);
a0486bac 227 return -1; /* errno is set for us. */
a30b3e18
NA
228 }
229
230 str = ctf_str_append (str, typestr);
231 free (typestr);
232
233 ctf_dump_append (state, str);
234 }
235 return 0;
236}
237
238/* Dump all the function entries into the cds_items. (As above, there is no
239 iterator for this section.) */
240
241static int
242ctf_dump_funcs (ctf_file_t *fp, ctf_dump_state_t *state)
243{
244 size_t i;
245
246 for (i = 0; i < fp->ctf_nsyms; i++)
247 {
248 char *str ;
249 char *bit;
250 const char *sym_name;
251 ctf_funcinfo_t fi;
252 ctf_id_t type;
253 size_t j;
254 ctf_id_t *args;
255
a0486bac 256 if ((type = ctf_func_info (state->cds_fp, i, &fi)) == CTF_ERR)
a30b3e18
NA
257 switch (ctf_errno (state->cds_fp))
258 {
259 /* Most errors are just an indication that this symbol is not a data
260 symbol, but this one indicates that we were called wrong, on a
261 CTF file with no associated symbol table. */
262 case ECTF_NOSYMTAB:
a0486bac 263 return -1;
a30b3e18
NA
264 case ECTF_NOTDATA:
265 case ECTF_NOTYPEDAT:
266 continue;
267 }
268 if ((args = calloc (fi.ctc_argc, sizeof (ctf_id_t))) == NULL)
269 return (ctf_set_errno (fp, ENOMEM));
270
271 /* Return type. */
272 if ((str = ctf_type_aname (state->cds_fp, type)) == NULL)
273 goto err;
274
275 str = ctf_str_append (str, " ");
276 free (bit);
277
278 /* Function name. */
279
280 sym_name = ctf_lookup_symbol_name (fp, i);
281 if (sym_name[0] == '\0')
282 {
283 if (asprintf (&bit, "%lx ", i) < 0)
284 goto oom;
285 }
286 else
287 {
288 if (asprintf (&bit, "%s (%lx) ", sym_name, i) < 0)
289 goto oom;
290 }
291 str = ctf_str_append (str, bit);
292 str = ctf_str_append (str, " (");
293
294 /* Function arguments. */
295
296 if (ctf_func_args (state->cds_fp, i, fi.ctc_argc, args) < 0)
297 goto err;
298
299 for (j = 0; j < fi.ctc_argc; j++)
300 {
301 if ((bit = ctf_type_aname (state->cds_fp, args[j])) == NULL)
302 goto err;
303 str = ctf_str_append (str, bit);
304 if ((j < fi.ctc_argc - 1) || (fi.ctc_flags & CTF_FUNC_VARARG))
305 str = ctf_str_append (str, ", ");
306 free (bit);
307 }
308
309 if (fi.ctc_flags & CTF_FUNC_VARARG)
310 str = ctf_str_append (str, "...");
311 str = ctf_str_append (str, ")");
312
313 free (args);
314 ctf_dump_append (state, str);
315 continue;
316
317 oom:
318 free (args);
319 free (str);
320 return (ctf_set_errno (fp, ENOMEM));
321 err:
322 free (args);
323 free (str);
a0486bac 324 return -1; /* errno is set for us. */
a30b3e18
NA
325 }
326 return 0;
327}
328
329/* Dump a single variable into the cds_items. */
330static int
331ctf_dump_var (const char *name, ctf_id_t type, void *arg)
332{
333 char *str;
334 char *typestr;
335 ctf_dump_state_t *state = arg;
336
337 if (asprintf (&str, "%s -> ", name) < 0)
338 return (ctf_set_errno (state->cds_fp, ENOMEM));
339
340 if ((typestr = ctf_dump_format_type (state->cds_fp, type)) == NULL)
341 {
342 free (str);
a0486bac 343 return -1; /* errno is set for us. */
a30b3e18
NA
344 }
345
346 str = ctf_str_append (str, typestr);
347 free (typestr);
348
349 ctf_dump_append (state, str);
350 return 0;
351}
352
353/* Dump a single member into the string in the membstate. */
354static int
355ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
356 int depth, void *arg)
357{
358 ctf_dump_membstate_t *state = arg;
359 char *typestr = NULL;
360 char *bit = NULL;
361 ctf_encoding_t ep;
362 ssize_t i;
363
364 for (i = 0; i < depth; i++)
365 *state->cdm_str = ctf_str_append (*state->cdm_str, " ");
366
367 if ((typestr = ctf_type_aname (state->cdm_fp, id)) == NULL)
368 goto oom;
369
370 if (asprintf (&bit, " [0x%lx] (ID 0x%lx) (kind %i) %s %s (aligned at 0x%lx",
371 offset, id, ctf_type_kind (state->cdm_fp, id), typestr, name,
372 ctf_type_align (state->cdm_fp, id)) < 0)
373 goto oom;
374 *state->cdm_str = ctf_str_append (*state->cdm_str, bit);
375 free (typestr);
376 free (bit);
377 typestr = NULL;
378 bit = NULL;
379
380 if ((ctf_type_kind (state->cdm_fp, id) == CTF_K_INTEGER)
381 || (ctf_type_kind (state->cdm_fp, id) == CTF_K_FLOAT)
382 || (ctf_is_slice (state->cdm_fp, id, &ep) == CTF_K_ENUM))
383 {
384 ctf_type_encoding (state->cdm_fp, id, &ep);
385 if (asprintf (&bit, ", format 0x%x, offset:bits 0x%x:0x%x", ep.cte_format,
386 ep.cte_offset, ep.cte_bits) < 0)
387 goto oom;
388 *state->cdm_str = ctf_str_append (*state->cdm_str, bit);
389 free (bit);
390 bit = NULL;
391 }
392
393 *state->cdm_str = ctf_str_append (*state->cdm_str, ")\n");
394 return 0;
395
396 oom:
397 free (typestr);
398 free (bit);
399 return (ctf_set_errno (state->cdm_fp, ENOMEM));
400}
401
402/* Dump a single type into the cds_items. */
403
404static int
405ctf_dump_type (ctf_id_t id, void *arg)
406{
407 char *str;
408 ctf_dump_state_t *state = arg;
409 ctf_dump_membstate_t membstate = { &str, state->cds_fp };
410 size_t len;
411
412 if ((str = ctf_dump_format_type (state->cds_fp, id)) == NULL)
413 goto err;
414
415 str = ctf_str_append (str, "\n");
416 if ((ctf_type_visit (state->cds_fp, id, ctf_dump_member, &membstate)) < 0)
417 goto err;
418
419 /* Trim off the last linefeed added by ctf_dump_member(). */
420 len = strlen (str);
421 if (str[len-1] == '\n')
422 str[len-1] = '\0';
423
424 ctf_dump_append (state, str);
425 return 0;
426
427 err:
428 free (str);
a0486bac 429 return -1; /* errno is set for us. */
a30b3e18
NA
430}
431
432/* Dump the string table into the cds_items. */
433
434static int
435ctf_dump_str (ctf_file_t *fp, ctf_dump_state_t *state)
436{
437 const char *s = fp->ctf_str[CTF_STRTAB_0].cts_strs;
438
439 for (; s < fp->ctf_str[CTF_STRTAB_0].cts_strs +
440 fp->ctf_str[CTF_STRTAB_0].cts_len;)
441 {
442 char *str;
443 if (asprintf (&str, "%lx: %s", s - fp->ctf_str[CTF_STRTAB_0].cts_strs,
444 s) < 0)
445 return (ctf_set_errno (fp, ENOMEM));
446 ctf_dump_append (state, str);
447 s += strlen (s) + 1;
448 }
449
450 return 0;
451}
452
453/* Dump a particular section of a CTF file, in textual form. Call with a
454 pointer to a NULL STATE: each call emits a dynamically allocated string
455 containing a description of one entity in the specified section, in order.
456 Only the first call (with a NULL state) may vary SECT. Once the CTF section
457 has been entirely dumped, the call returns NULL and frees and annuls the
458 STATE, ready for another section to be dumped. The returned textual content
459 may span multiple lines: between each call the FUNC is called with one
460 textual line at a time, and should return a suitably decorated line (it can
461 allocate a new one and return it if it likes). */
462
463char *
464ctf_dump (ctf_file_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
465 ctf_dump_decorate_f *func, void *arg)
466{
467 char *str;
468 char *line;
469 ctf_dump_state_t *state = NULL;
470
471 if (*statep == NULL)
472 {
473 /* Data collection. Transforming a call-at-a-time iterator into a
474 return-at-a-time iterator in a language without call/cc is annoying. It
475 is easiest to simply collect everything at once and then return it bit
476 by bit. The first call will take (much) longer than otherwise, but the
477 amortized time needed is the same. */
478
479 if ((*statep = ctf_alloc (sizeof (struct ctf_dump_state))) == NULL)
480 {
481 ctf_set_errno (fp, ENOMEM);
482 goto end;
483 }
484 state = *statep;
485
486 memset (state, 0, sizeof (struct ctf_dump_state));
487 state->cds_fp = fp;
488 state->cds_sect = sect;
489
490 switch (sect)
491 {
492 case CTF_SECT_HEADER:
493 /* Nothing doable (yet): entire header is discarded after read-phase. */
494 str = strdup ("");
495 break;
496 case CTF_SECT_LABEL:
497 if (ctf_label_iter (fp, ctf_dump_label, state) < 0)
498 {
499 if (ctf_errno (fp) != ECTF_NOLABELDATA)
500 goto end; /* errno is set for us. */
501 ctf_set_errno (fp, 0);
502 }
503 break;
504 case CTF_SECT_OBJT:
505 if (ctf_dump_objts (fp, state) < 0)
506 goto end; /* errno is set for us. */
507 break;
508 case CTF_SECT_FUNC:
509 if (ctf_dump_funcs (fp, state) < 0)
510 goto end; /* errno is set for us. */
511 break;
512 case CTF_SECT_VAR:
513 if (ctf_variable_iter (fp, ctf_dump_var, state) < 0)
514 goto end; /* errno is set for us. */
515 break;
516 case CTF_SECT_TYPE:
517 if (ctf_type_iter (fp, ctf_dump_type, state) < 0)
518 goto end; /* errno is set for us. */
519 break;
520 case CTF_SECT_STR:
521 ctf_dump_str (fp, state);
522 break;
523 default:
524 ctf_set_errno (fp, ECTF_DUMPSECTUNKNOWN);
525 goto end;
526 }
527 }
528 else
529 {
530 state = *statep;
531
532 if (state->cds_sect != sect)
533 {
534 ctf_set_errno (fp, ECTF_DUMPSECTCHANGED);
535 goto end;
536 }
537 }
538
539 if (state->cds_current == NULL)
540 state->cds_current = ctf_list_next (&state->cds_items);
541 else
542 state->cds_current = ctf_list_next (state->cds_current);
543
544 if (state->cds_current == NULL)
545 goto end;
546
547 /* Hookery. There is some extra complexity to preserve linefeeds within each
548 item while removing linefeeds at the end. */
549 if (func)
550 {
551 size_t len;
552
553 str = NULL;
554 for (line = state->cds_current->cdi_item; line && *line; )
555 {
556 char *nline = line;
557 char *ret;
558
559 nline = strchr (line, '\n');
560 if (nline)
561 nline[0] = '\0';
562
563 ret = func (sect, line, arg);
564 str = ctf_str_append (str, ret);
565 str = ctf_str_append (str, "\n");
566 if (ret != line)
567 free (ret);
568
569 if (nline)
570 {
571 nline[0] = '\n';
572 nline++;
573 }
574
575 line = nline;
576 }
577
578 len = strlen (str);
579
580 if (str[len-1] == '\n')
581 str[len-1] = '\0';
582 }
583 else
584 str = strdup (state->cds_current->cdi_item);
585
586 ctf_set_errno (fp, 0);
587 return str;
588
589 end:
590 ctf_dump_free (state);
591 ctf_free (state);
592 ctf_set_errno (fp, 0);
593 *statep = NULL;
594 return NULL;
595}
This page took 0.145893 seconds and 4 git commands to generate.