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