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 <gelf.h>
25
26 ctf_convert_f ctf_converters[] = {
27 ctf_dwarf_convert
28 };
29
30 #define NCONVERTS (sizeof (ctf_converters) / sizeof (ctf_convert_f))
31
32 typedef enum ctf_convert_source {
33 CTFCONV_SOURCE_NONE = 0x0,
34 CTFCONV_SOURCE_UNKNOWN = 0x01,
35 CTFCONV_SOURCE_C = 0x02,
36 CTFCONV_SOURCE_S = 0x04
37 } ctf_convert_source_t;
38
39 static void
40 ctf_convert_ftypes(Elf *elf, ctf_convert_source_t *types)
41 {
42 int i;
43 Elf_Scn *scn = NULL, *strscn;
44 *types = CTFCONV_SOURCE_NONE;
45 GElf_Shdr shdr;
46 Elf_Data *data, *strdata;
47
48 while ((scn = elf_nextscn(elf, scn)) != NULL) {
49
50 if (gelf_getshdr(scn, &shdr) == NULL)
51 return;
52
53 if (shdr.sh_type == SHT_SYMTAB)
54 break;
55 }
56
57 if (scn == NULL)
58 return;
59
60 if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL)
61 return;
62
63 if ((data = elf_getdata(scn, NULL)) == NULL)
64 return;
65
66 if ((strdata = elf_getdata(strscn, NULL)) == NULL)
67 return;
68
69 for (i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
70 GElf_Sym sym;
71 const char *file;
72 size_t len;
73
74 if (gelf_getsym(data, i, &sym) == NULL)
75 return;
76
77 if (GELF_ST_TYPE(sym.st_info) != STT_FILE)
78 continue;
79
80 file = (const char *)((uintptr_t)strdata->d_buf + sym.st_name);
81 len = strlen(file);
82 if (len < 2 || file[len - 2] != '.') {
83 *types |= CTFCONV_SOURCE_UNKNOWN;
84 continue;
85 }
86
87 switch (file[len - 1]) {
88 case 'c':
89 *types |= CTFCONV_SOURCE_C;
90 break;
91 case 'h':
92 /* We traditionally ignore header files... */
93 break;
94 case 's':
95 *types |= CTFCONV_SOURCE_S;
96 break;
97 default:
98 *types |= CTFCONV_SOURCE_UNKNOWN;
99 break;
100 }
101 }
102 }
103
104 static ctf_file_t *
105 ctf_elfconvert(int fd, Elf *elf, const char *label, uint_t nthrs, uint_t flags,
106 int *errp, char *errbuf, size_t errlen)
107 {
108 int err, i;
109 ctf_file_t *fp = NULL;
110 boolean_t notsup = B_TRUE;
111 ctf_convert_source_t type;
112
113 if (errp == NULL)
114 errp = &err;
115
116 if (elf == NULL) {
117 *errp = EINVAL;
118 return (NULL);
119 }
120
121 if (flags & ~CTF_CONVERT_F_IGNNONC) {
122 *errp = EINVAL;
123 return (NULL);
124 }
125
126 if (elf_kind(elf) != ELF_K_ELF) {
127 *errp = ECTF_FMT;
128 return (NULL);
129 }
130
131 ctf_convert_ftypes(elf, &type);
132 ctf_dprintf("got types: %d\n", type);
133 if (flags & CTF_CONVERT_F_IGNNONC) {
134 if (type == CTFCONV_SOURCE_NONE ||
135 (type & CTFCONV_SOURCE_UNKNOWN)) {
136 *errp = ECTF_CONVNOCSRC;
137 return (NULL);
138 }
139 }
140
141 for (i = 0; i < NCONVERTS; i++) {
142 ctf_conv_status_t cs;
143
144 fp = NULL;
145 cs = ctf_converters[i](fd, elf, nthrs, errp, &fp, errbuf,
146 errlen);
147 if (cs == CTF_CONV_SUCCESS) {
148 notsup = B_FALSE;
149 break;
150 }
151 if (cs == CTF_CONV_ERROR) {
152 fp = NULL;
153 notsup = B_FALSE;
154 break;
155 }
156 }
157
158 if (notsup == B_TRUE) {
159 if ((flags & CTF_CONVERT_F_IGNNONC) != 0 &&
160 (type & CTFCONV_SOURCE_C) == 0) {
161 *errp = ECTF_CONVNOCSRC;
162 return (NULL);
163 }
164 *errp = ECTF_NOCONVBKEND;
165 return (NULL);
166 }
167
168 /*
169 * Succsesful conversion.
170 */
171 if (fp != NULL && label != NULL) {
172 if (ctf_add_label(fp, label, fp->ctf_typemax, 0) == CTF_ERR) {
173 *errp = ctf_errno(fp);
174 ctf_close(fp);
175 return (NULL);
176 }
177 if (ctf_update(fp) == CTF_ERR) {
178 *errp = ctf_errno(fp);
179 ctf_close(fp);
180 return (NULL);
181 }
182 }
183
184 return (fp);
185 }
186
187 ctf_file_t *
188 ctf_fdconvert(int fd, const char *label, uint_t nthrs, uint_t flags, int *errp,
189 char *errbuf, size_t errlen)
190 {
191 int err;
|
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;
|