1*7fd79137SRobert Mustacchi /* 2*7fd79137SRobert Mustacchi * This file and its contents are supplied under the terms of the 3*7fd79137SRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0. 4*7fd79137SRobert Mustacchi * You may only use this file in accordance with the terms of version 5*7fd79137SRobert Mustacchi * 1.0 of the CDDL. 6*7fd79137SRobert Mustacchi * 7*7fd79137SRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this 8*7fd79137SRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at 9*7fd79137SRobert Mustacchi * http://www.illumos.org/license/CDDL. 10*7fd79137SRobert Mustacchi */ 11*7fd79137SRobert Mustacchi 12*7fd79137SRobert Mustacchi /* 13*7fd79137SRobert Mustacchi * Copyright 2015 Joyent, Inc. 14*7fd79137SRobert Mustacchi */ 15*7fd79137SRobert Mustacchi 16*7fd79137SRobert Mustacchi /* 17*7fd79137SRobert Mustacchi * Main conversion entry points. This has been designed such that there can be 18*7fd79137SRobert Mustacchi * any number of different conversion backends. Currently we only have one that 19*7fd79137SRobert Mustacchi * understands DWARFv2 (and bits of DWARFv4). Each backend should be placed in 20*7fd79137SRobert Mustacchi * the ctf_converters list and each will be tried in turn. 21*7fd79137SRobert Mustacchi */ 22*7fd79137SRobert Mustacchi 23*7fd79137SRobert Mustacchi #include <libctf_impl.h> 24*7fd79137SRobert Mustacchi #include <gelf.h> 25*7fd79137SRobert Mustacchi 26*7fd79137SRobert Mustacchi ctf_convert_f ctf_converters[] = { 27*7fd79137SRobert Mustacchi ctf_dwarf_convert 28*7fd79137SRobert Mustacchi }; 29*7fd79137SRobert Mustacchi 30*7fd79137SRobert Mustacchi #define NCONVERTS (sizeof (ctf_converters) / sizeof (ctf_convert_f)) 31*7fd79137SRobert Mustacchi 32*7fd79137SRobert Mustacchi typedef enum ctf_convert_source { 33*7fd79137SRobert Mustacchi CTFCONV_SOURCE_NONE = 0x0, 34*7fd79137SRobert Mustacchi CTFCONV_SOURCE_UNKNOWN = 0x01, 35*7fd79137SRobert Mustacchi CTFCONV_SOURCE_C = 0x02, 36*7fd79137SRobert Mustacchi CTFCONV_SOURCE_S = 0x04 37*7fd79137SRobert Mustacchi } ctf_convert_source_t; 38*7fd79137SRobert Mustacchi 39*7fd79137SRobert Mustacchi static void 40*7fd79137SRobert Mustacchi ctf_convert_ftypes(Elf *elf, ctf_convert_source_t *types) 41*7fd79137SRobert Mustacchi { 42*7fd79137SRobert Mustacchi int i; 43*7fd79137SRobert Mustacchi Elf_Scn *scn = NULL, *strscn; 44*7fd79137SRobert Mustacchi *types = CTFCONV_SOURCE_NONE; 45*7fd79137SRobert Mustacchi GElf_Shdr shdr; 46*7fd79137SRobert Mustacchi Elf_Data *data, *strdata; 47*7fd79137SRobert Mustacchi 48*7fd79137SRobert Mustacchi while ((scn = elf_nextscn(elf, scn)) != NULL) { 49*7fd79137SRobert Mustacchi 50*7fd79137SRobert Mustacchi if (gelf_getshdr(scn, &shdr) == NULL) 51*7fd79137SRobert Mustacchi return; 52*7fd79137SRobert Mustacchi 53*7fd79137SRobert Mustacchi if (shdr.sh_type == SHT_SYMTAB) 54*7fd79137SRobert Mustacchi break; 55*7fd79137SRobert Mustacchi } 56*7fd79137SRobert Mustacchi 57*7fd79137SRobert Mustacchi if (scn == NULL) 58*7fd79137SRobert Mustacchi return; 59*7fd79137SRobert Mustacchi 60*7fd79137SRobert Mustacchi if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL) 61*7fd79137SRobert Mustacchi return; 62*7fd79137SRobert Mustacchi 63*7fd79137SRobert Mustacchi if ((data = elf_getdata(scn, NULL)) == NULL) 64*7fd79137SRobert Mustacchi return; 65*7fd79137SRobert Mustacchi 66*7fd79137SRobert Mustacchi if ((strdata = elf_getdata(strscn, NULL)) == NULL) 67*7fd79137SRobert Mustacchi return; 68*7fd79137SRobert Mustacchi 69*7fd79137SRobert Mustacchi for (i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) { 70*7fd79137SRobert Mustacchi GElf_Sym sym; 71*7fd79137SRobert Mustacchi const char *file; 72*7fd79137SRobert Mustacchi size_t len; 73*7fd79137SRobert Mustacchi 74*7fd79137SRobert Mustacchi if (gelf_getsym(data, i, &sym) == NULL) 75*7fd79137SRobert Mustacchi return; 76*7fd79137SRobert Mustacchi 77*7fd79137SRobert Mustacchi if (GELF_ST_TYPE(sym.st_info) != STT_FILE) 78*7fd79137SRobert Mustacchi continue; 79*7fd79137SRobert Mustacchi 80*7fd79137SRobert Mustacchi file = (const char *)((uintptr_t)strdata->d_buf + sym.st_name); 81*7fd79137SRobert Mustacchi len = strlen(file); 82*7fd79137SRobert Mustacchi if (len < 2 || file[len - 2] != '.') { 83*7fd79137SRobert Mustacchi *types |= CTFCONV_SOURCE_UNKNOWN; 84*7fd79137SRobert Mustacchi continue; 85*7fd79137SRobert Mustacchi } 86*7fd79137SRobert Mustacchi 87*7fd79137SRobert Mustacchi switch (file[len - 1]) { 88*7fd79137SRobert Mustacchi case 'c': 89*7fd79137SRobert Mustacchi *types |= CTFCONV_SOURCE_C; 90*7fd79137SRobert Mustacchi break; 91*7fd79137SRobert Mustacchi case 'h': 92*7fd79137SRobert Mustacchi /* We traditionally ignore header files... */ 93*7fd79137SRobert Mustacchi break; 94*7fd79137SRobert Mustacchi case 's': 95*7fd79137SRobert Mustacchi *types |= CTFCONV_SOURCE_S; 96*7fd79137SRobert Mustacchi break; 97*7fd79137SRobert Mustacchi default: 98*7fd79137SRobert Mustacchi *types |= CTFCONV_SOURCE_UNKNOWN; 99*7fd79137SRobert Mustacchi break; 100*7fd79137SRobert Mustacchi } 101*7fd79137SRobert Mustacchi } 102*7fd79137SRobert Mustacchi } 103*7fd79137SRobert Mustacchi 104*7fd79137SRobert Mustacchi static ctf_file_t * 105*7fd79137SRobert Mustacchi ctf_elfconvert(int fd, Elf *elf, const char *label, uint_t nthrs, uint_t flags, 106*7fd79137SRobert Mustacchi int *errp, char *errbuf, size_t errlen) 107*7fd79137SRobert Mustacchi { 108*7fd79137SRobert Mustacchi int err, i; 109*7fd79137SRobert Mustacchi ctf_file_t *fp = NULL; 110*7fd79137SRobert Mustacchi boolean_t notsup = B_TRUE; 111*7fd79137SRobert Mustacchi ctf_convert_source_t type; 112*7fd79137SRobert Mustacchi 113*7fd79137SRobert Mustacchi if (errp == NULL) 114*7fd79137SRobert Mustacchi errp = &err; 115*7fd79137SRobert Mustacchi 116*7fd79137SRobert Mustacchi if (elf == NULL) { 117*7fd79137SRobert Mustacchi *errp = EINVAL; 118*7fd79137SRobert Mustacchi return (NULL); 119*7fd79137SRobert Mustacchi } 120*7fd79137SRobert Mustacchi 121*7fd79137SRobert Mustacchi if (flags & ~CTF_CONVERT_F_IGNNONC) { 122*7fd79137SRobert Mustacchi *errp = EINVAL; 123*7fd79137SRobert Mustacchi return (NULL); 124*7fd79137SRobert Mustacchi } 125*7fd79137SRobert Mustacchi 126*7fd79137SRobert Mustacchi if (elf_kind(elf) != ELF_K_ELF) { 127*7fd79137SRobert Mustacchi *errp = ECTF_FMT; 128*7fd79137SRobert Mustacchi return (NULL); 129*7fd79137SRobert Mustacchi } 130*7fd79137SRobert Mustacchi 131*7fd79137SRobert Mustacchi ctf_convert_ftypes(elf, &type); 132*7fd79137SRobert Mustacchi ctf_dprintf("got types: %d\n", type); 133*7fd79137SRobert Mustacchi if (flags & CTF_CONVERT_F_IGNNONC) { 134*7fd79137SRobert Mustacchi if (type == CTFCONV_SOURCE_NONE || 135*7fd79137SRobert Mustacchi (type & CTFCONV_SOURCE_UNKNOWN)) { 136*7fd79137SRobert Mustacchi *errp = ECTF_CONVNOCSRC; 137*7fd79137SRobert Mustacchi return (NULL); 138*7fd79137SRobert Mustacchi } 139*7fd79137SRobert Mustacchi } 140*7fd79137SRobert Mustacchi 141*7fd79137SRobert Mustacchi for (i = 0; i < NCONVERTS; i++) { 142*7fd79137SRobert Mustacchi ctf_conv_status_t cs; 143*7fd79137SRobert Mustacchi 144*7fd79137SRobert Mustacchi fp = NULL; 145*7fd79137SRobert Mustacchi cs = ctf_converters[i](fd, elf, nthrs, errp, &fp, errbuf, 146*7fd79137SRobert Mustacchi errlen); 147*7fd79137SRobert Mustacchi if (cs == CTF_CONV_SUCCESS) { 148*7fd79137SRobert Mustacchi notsup = B_FALSE; 149*7fd79137SRobert Mustacchi break; 150*7fd79137SRobert Mustacchi } 151*7fd79137SRobert Mustacchi if (cs == CTF_CONV_ERROR) { 152*7fd79137SRobert Mustacchi fp = NULL; 153*7fd79137SRobert Mustacchi notsup = B_FALSE; 154*7fd79137SRobert Mustacchi break; 155*7fd79137SRobert Mustacchi } 156*7fd79137SRobert Mustacchi } 157*7fd79137SRobert Mustacchi 158*7fd79137SRobert Mustacchi if (notsup == B_TRUE) { 159*7fd79137SRobert Mustacchi if ((flags & CTF_CONVERT_F_IGNNONC) != 0 && 160*7fd79137SRobert Mustacchi (type & CTFCONV_SOURCE_C) == 0) { 161*7fd79137SRobert Mustacchi *errp = ECTF_CONVNOCSRC; 162*7fd79137SRobert Mustacchi return (NULL); 163*7fd79137SRobert Mustacchi } 164*7fd79137SRobert Mustacchi *errp = ECTF_NOCONVBKEND; 165*7fd79137SRobert Mustacchi return (NULL); 166*7fd79137SRobert Mustacchi } 167*7fd79137SRobert Mustacchi 168*7fd79137SRobert Mustacchi /* 169*7fd79137SRobert Mustacchi * Succsesful conversion. 170*7fd79137SRobert Mustacchi */ 171*7fd79137SRobert Mustacchi if (fp != NULL) { 172*7fd79137SRobert Mustacchi if (label == NULL) 173*7fd79137SRobert Mustacchi label = ""; 174*7fd79137SRobert Mustacchi if (ctf_add_label(fp, label, fp->ctf_typemax, 0) == CTF_ERR) { 175*7fd79137SRobert Mustacchi *errp = ctf_errno(fp); 176*7fd79137SRobert Mustacchi ctf_close(fp); 177*7fd79137SRobert Mustacchi return (NULL); 178*7fd79137SRobert Mustacchi } 179*7fd79137SRobert Mustacchi if (ctf_update(fp) == CTF_ERR) { 180*7fd79137SRobert Mustacchi *errp = ctf_errno(fp); 181*7fd79137SRobert Mustacchi ctf_close(fp); 182*7fd79137SRobert Mustacchi return (NULL); 183*7fd79137SRobert Mustacchi } 184*7fd79137SRobert Mustacchi } 185*7fd79137SRobert Mustacchi 186*7fd79137SRobert Mustacchi return (fp); 187*7fd79137SRobert Mustacchi } 188*7fd79137SRobert Mustacchi 189*7fd79137SRobert Mustacchi ctf_file_t * 190*7fd79137SRobert Mustacchi ctf_fdconvert(int fd, const char *label, uint_t nthrs, uint_t flags, int *errp, 191*7fd79137SRobert Mustacchi char *errbuf, size_t errlen) 192*7fd79137SRobert Mustacchi { 193*7fd79137SRobert Mustacchi int err; 194*7fd79137SRobert Mustacchi Elf *elf; 195*7fd79137SRobert Mustacchi ctf_file_t *fp; 196*7fd79137SRobert Mustacchi 197*7fd79137SRobert Mustacchi if (errp == NULL) 198*7fd79137SRobert Mustacchi errp = &err; 199*7fd79137SRobert Mustacchi 200*7fd79137SRobert Mustacchi elf = elf_begin(fd, ELF_C_READ, NULL); 201*7fd79137SRobert Mustacchi if (elf == NULL) { 202*7fd79137SRobert Mustacchi *errp = ECTF_FMT; 203*7fd79137SRobert Mustacchi return (NULL); 204*7fd79137SRobert Mustacchi } 205*7fd79137SRobert Mustacchi 206*7fd79137SRobert Mustacchi fp = ctf_elfconvert(fd, elf, label, nthrs, flags, errp, errbuf, errlen); 207*7fd79137SRobert Mustacchi 208*7fd79137SRobert Mustacchi (void) elf_end(elf); 209*7fd79137SRobert Mustacchi return (fp); 210*7fd79137SRobert Mustacchi } 211