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