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