xref: /illumos-gate/usr/src/lib/libctf/common/ctf_convert.c (revision 077efea49519c17f19d69473223f9664f3c94812)
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  }
193