libctf: work on platforms without O_CLOEXEC.
[external/binutils.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)
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
157 static int
158 ctf_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);
171       return -1;                        /* errno is set for us.  */
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
185 static int
186 ctf_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
197       if ((type = ctf_lookup_by_symbol (state->cds_fp, i)) == CTF_ERR)
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:
204             return -1;
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);
227           return -1;                    /* errno is set for us.  */
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
241 static int
242 ctf_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
256       if ((type = ctf_func_info (state->cds_fp, i, &fi)) == CTF_ERR)
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:
263             return -1;
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
277       /* Function name.  */
278
279       sym_name = ctf_lookup_symbol_name (fp, i);
280       if (sym_name[0] == '\0')
281         {
282           if (asprintf (&bit, "%lx ", i) < 0)
283             goto oom;
284         }
285       else
286         {
287           if (asprintf (&bit, "%s (%lx) ", sym_name, i) < 0)
288             goto oom;
289         }
290       str = ctf_str_append (str, bit);
291       str = ctf_str_append (str, " (");
292       free (bit);
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);
324       return -1;                /* errno is set for us.  */
325     }
326   return 0;
327 }
328
329 /* Dump a single variable into the cds_items.  */
330 static int
331 ctf_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);
343       return -1;                        /* errno is set for us.  */
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.  */
354 static int
355 ctf_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
404 static int
405 ctf_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);
429   return -1;                            /* errno is set for us.  */
430 }
431
432 /* Dump the string table into the cds_items.  */
433
434 static int
435 ctf_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
463 char *
464 ctf_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 }