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