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