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