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
ctf_convert_ftypes(Elf * elf,ctf_convert_source_t * types)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 *
ctf_elfconvert(int fd,Elf * elf,const char * label,uint_t nthrs,uint_t flags,int * errp,char * errbuf,size_t errlen)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 *
ctf_fdconvert(int fd,const char * label,uint_t nthrs,uint_t flags,int * errp,char * errbuf,size_t errlen)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