1*5bb525f4SRobert Mustacchi /*
2*5bb525f4SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*5bb525f4SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*5bb525f4SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*5bb525f4SRobert Mustacchi  * 1.0 of the CDDL.
6*5bb525f4SRobert Mustacchi  *
7*5bb525f4SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*5bb525f4SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*5bb525f4SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*5bb525f4SRobert Mustacchi  */
11*5bb525f4SRobert Mustacchi 
12*5bb525f4SRobert Mustacchi /*
13*5bb525f4SRobert Mustacchi  * Copyright (c) 2019, Joyent, Inc.
14*5bb525f4SRobert Mustacchi  */
15*5bb525f4SRobert Mustacchi 
16*5bb525f4SRobert Mustacchi /*
17*5bb525f4SRobert Mustacchi  * Verify that various type information for static symbols is accurate for the
18*5bb525f4SRobert Mustacchi  * file in question. To run this test, there's a global and static version of a
19*5bb525f4SRobert Mustacchi  * symbol and function that exists on a per-file basis. These will all have been
20*5bb525f4SRobert Mustacchi  * reproduced in the output file. As such, we need to iterate the symbol table
21*5bb525f4SRobert Mustacchi  * to know which version should be which and use that to drive things.
22*5bb525f4SRobert Mustacchi  */
23*5bb525f4SRobert Mustacchi 
24*5bb525f4SRobert Mustacchi #include <sys/types.h>
25*5bb525f4SRobert Mustacchi #include <sys/stat.h>
26*5bb525f4SRobert Mustacchi #include <fcntl.h>
27*5bb525f4SRobert Mustacchi #include <libelf.h>
28*5bb525f4SRobert Mustacchi #include <gelf.h>
29*5bb525f4SRobert Mustacchi #include <limits.h>
30*5bb525f4SRobert Mustacchi #include <strings.h>
31*5bb525f4SRobert Mustacchi 
32*5bb525f4SRobert Mustacchi #include "check-common.h"
33*5bb525f4SRobert Mustacchi 
34*5bb525f4SRobert Mustacchi typedef struct check_map {
35*5bb525f4SRobert Mustacchi 	const char *map_file;
36*5bb525f4SRobert Mustacchi 	const char *map_type;
37*5bb525f4SRobert Mustacchi } check_map_t;
38*5bb525f4SRobert Mustacchi 
39*5bb525f4SRobert Mustacchi static const char *global_type = "int";
40*5bb525f4SRobert Mustacchi static check_map_t map[] = {
41*5bb525f4SRobert Mustacchi 	{ "test-a.c", "uint8_t" },
42*5bb525f4SRobert Mustacchi 	{ "test-b.c", "uint16_t" },
43*5bb525f4SRobert Mustacchi 	{ "test-c.c", "uint32_t" },
44*5bb525f4SRobert Mustacchi 	{ "test-d.c", "uint64_t" },
45*5bb525f4SRobert Mustacchi 	{ NULL }
46*5bb525f4SRobert Mustacchi };
47*5bb525f4SRobert Mustacchi 
48*5bb525f4SRobert Mustacchi static const char *
check_file_to_type(GElf_Sym * symp,const char * file,const char * name)49*5bb525f4SRobert Mustacchi check_file_to_type(GElf_Sym *symp, const char *file, const char *name)
50*5bb525f4SRobert Mustacchi {
51*5bb525f4SRobert Mustacchi 	uint_t i;
52*5bb525f4SRobert Mustacchi 
53*5bb525f4SRobert Mustacchi 	if (ELF32_ST_BIND(symp->st_info) == STB_GLOBAL) {
54*5bb525f4SRobert Mustacchi 		return (global_type);
55*5bb525f4SRobert Mustacchi 	}
56*5bb525f4SRobert Mustacchi 
57*5bb525f4SRobert Mustacchi 	if (file == NULL) {
58*5bb525f4SRobert Mustacchi 		warnx("encountered non-global symbol without STT_FILE info: %s",
59*5bb525f4SRobert Mustacchi 		    name);
60*5bb525f4SRobert Mustacchi 		return (NULL);
61*5bb525f4SRobert Mustacchi 	}
62*5bb525f4SRobert Mustacchi 
63*5bb525f4SRobert Mustacchi 	for (i = 0; map[i].map_file != NULL; i++) {
64*5bb525f4SRobert Mustacchi 		if (strcmp(map[i].map_file, file) == 0) {
65*5bb525f4SRobert Mustacchi 			return (map[i].map_type);
66*5bb525f4SRobert Mustacchi 		}
67*5bb525f4SRobert Mustacchi 	}
68*5bb525f4SRobert Mustacchi 
69*5bb525f4SRobert Mustacchi 	warnx("failed to find type mapping for symbol %s, file %s", name, file);
70*5bb525f4SRobert Mustacchi 	return (NULL);
71*5bb525f4SRobert Mustacchi }
72*5bb525f4SRobert Mustacchi 
73*5bb525f4SRobert Mustacchi static int
check_global(ctf_file_t * fp,GElf_Sym * symp,int symid,const char * file,const char * name)74*5bb525f4SRobert Mustacchi check_global(ctf_file_t *fp, GElf_Sym *symp, int symid, const char *file,
75*5bb525f4SRobert Mustacchi     const char *name)
76*5bb525f4SRobert Mustacchi {
77*5bb525f4SRobert Mustacchi 	const char *type;
78*5bb525f4SRobert Mustacchi 	ctf_id_t tid;
79*5bb525f4SRobert Mustacchi 	char buf[2048];
80*5bb525f4SRobert Mustacchi 
81*5bb525f4SRobert Mustacchi 	if ((type = check_file_to_type(symp, file, name)) == NULL) {
82*5bb525f4SRobert Mustacchi 		return (EXIT_FAILURE);
83*5bb525f4SRobert Mustacchi 	}
84*5bb525f4SRobert Mustacchi 
85*5bb525f4SRobert Mustacchi 	if ((tid = ctf_lookup_by_symbol(fp, symid)) == CTF_ERR) {
86*5bb525f4SRobert Mustacchi 		warnx("failed to get type for symbol %s (%d): %s", name, symid,
87*5bb525f4SRobert Mustacchi 		    ctf_errmsg(ctf_errno(fp)));
88*5bb525f4SRobert Mustacchi 		return (EXIT_FAILURE);
89*5bb525f4SRobert Mustacchi 	}
90*5bb525f4SRobert Mustacchi 
91*5bb525f4SRobert Mustacchi 	if (ctf_type_name(fp, tid, buf, sizeof (buf)) == NULL) {
92*5bb525f4SRobert Mustacchi 		warnx("failed to get type name for symbol %s (%d): %s",
93*5bb525f4SRobert Mustacchi 		    name, symid, ctf_errmsg(ctf_errno(fp)));
94*5bb525f4SRobert Mustacchi 		return (EXIT_FAILURE);
95*5bb525f4SRobert Mustacchi 	}
96*5bb525f4SRobert Mustacchi 
97*5bb525f4SRobert Mustacchi 	if (strcmp(buf, type) != 0) {
98*5bb525f4SRobert Mustacchi 		warnx("type mismatch for symbol %s (%d): found %s, expected %s",
99*5bb525f4SRobert Mustacchi 		    name, symid, buf, type);
100*5bb525f4SRobert Mustacchi 		return (EXIT_FAILURE);
101*5bb525f4SRobert Mustacchi 	}
102*5bb525f4SRobert Mustacchi 
103*5bb525f4SRobert Mustacchi 	return (0);
104*5bb525f4SRobert Mustacchi }
105*5bb525f4SRobert Mustacchi 
106*5bb525f4SRobert Mustacchi static int
check_mumble(ctf_file_t * fp,GElf_Sym * symp,int symid,const char * file,const char * name)107*5bb525f4SRobert Mustacchi check_mumble(ctf_file_t *fp, GElf_Sym *symp, int symid, const char *file,
108*5bb525f4SRobert Mustacchi     const char *name)
109*5bb525f4SRobert Mustacchi {
110*5bb525f4SRobert Mustacchi 	const char *type;
111*5bb525f4SRobert Mustacchi 	ctf_funcinfo_t fi;
112*5bb525f4SRobert Mustacchi 	ctf_id_t id, args;
113*5bb525f4SRobert Mustacchi 
114*5bb525f4SRobert Mustacchi 	if ((type = check_file_to_type(symp, file, name)) == NULL) {
115*5bb525f4SRobert Mustacchi 		return (EXIT_FAILURE);
116*5bb525f4SRobert Mustacchi 	}
117*5bb525f4SRobert Mustacchi 
118*5bb525f4SRobert Mustacchi 	if ((id = ctf_lookup_by_name(fp, type)) == CTF_ERR) {
119*5bb525f4SRobert Mustacchi 		warnx("failed to lookup type id for %s: %s", type,
120*5bb525f4SRobert Mustacchi 		    ctf_errmsg(ctf_errno(fp)));
121*5bb525f4SRobert Mustacchi 		return (EXIT_FAILURE);
122*5bb525f4SRobert Mustacchi 	}
123*5bb525f4SRobert Mustacchi 
124*5bb525f4SRobert Mustacchi 	if (ctf_func_info(fp, symid, &fi) != 0) {
125*5bb525f4SRobert Mustacchi 		warnx("failed to get function information for %s (%d): %s",
126*5bb525f4SRobert Mustacchi 		    name, symid, ctf_errmsg(ctf_errno(fp)));
127*5bb525f4SRobert Mustacchi 		return (EXIT_FAILURE);
128*5bb525f4SRobert Mustacchi 	}
129*5bb525f4SRobert Mustacchi 
130*5bb525f4SRobert Mustacchi 	if (fi.ctc_argc != 1) {
131*5bb525f4SRobert Mustacchi 		warnx("argument count mismatch for symbol %s (%d): found %u, "
132*5bb525f4SRobert Mustacchi 		    "expected %d", name, symid, fi.ctc_argc, 1);
133*5bb525f4SRobert Mustacchi 		return (EXIT_FAILURE);
134*5bb525f4SRobert Mustacchi 	}
135*5bb525f4SRobert Mustacchi 
136*5bb525f4SRobert Mustacchi 	if (fi.ctc_flags != 0) {
137*5bb525f4SRobert Mustacchi 		warnx("function flags mismatch for symbol %s (%d): found %u, "
138*5bb525f4SRobert Mustacchi 		    "expected %d", name, symid, fi.ctc_flags, 0);
139*5bb525f4SRobert Mustacchi 		return (EXIT_FAILURE);
140*5bb525f4SRobert Mustacchi 	}
141*5bb525f4SRobert Mustacchi 
142*5bb525f4SRobert Mustacchi 	if (fi.ctc_return != id) {
143*5bb525f4SRobert Mustacchi 		warnx("return value mismatch for symbol %s (%d): found %ld, "
144*5bb525f4SRobert Mustacchi 		    "expected %ld", name, symid, fi.ctc_return, id);
145*5bb525f4SRobert Mustacchi 		return (EXIT_FAILURE);
146*5bb525f4SRobert Mustacchi 	}
147*5bb525f4SRobert Mustacchi 
148*5bb525f4SRobert Mustacchi 	if (ctf_func_args(fp, symid, 1, &args) != 0) {
149*5bb525f4SRobert Mustacchi 		warnx("failed to get function arguments for symbol %s (%d): %s",
150*5bb525f4SRobert Mustacchi 		    name, symid, ctf_errmsg(ctf_errno(fp)));
151*5bb525f4SRobert Mustacchi 		return (EXIT_FAILURE);
152*5bb525f4SRobert Mustacchi 	}
153*5bb525f4SRobert Mustacchi 
154*5bb525f4SRobert Mustacchi 	if (args != id) {
155*5bb525f4SRobert Mustacchi 		warnx("argument mismatch for symbol %s (%d): found %ld, "
156*5bb525f4SRobert Mustacchi 		    "expected %ld", name, symid, args, id);
157*5bb525f4SRobert Mustacchi 		return (EXIT_FAILURE);
158*5bb525f4SRobert Mustacchi 	}
159*5bb525f4SRobert Mustacchi 
160*5bb525f4SRobert Mustacchi 	return (0);
161*5bb525f4SRobert Mustacchi }
162*5bb525f4SRobert Mustacchi 
163*5bb525f4SRobert Mustacchi static int
check_merge_static(const char * file,ctf_file_t * fp,Elf * elf)164*5bb525f4SRobert Mustacchi check_merge_static(const char *file, ctf_file_t *fp, Elf *elf)
165*5bb525f4SRobert Mustacchi {
166*5bb525f4SRobert Mustacchi 	Elf_Scn *scn = NULL, *symscn = NULL;
167*5bb525f4SRobert Mustacchi 	Elf_Data *symdata = NULL;
168*5bb525f4SRobert Mustacchi 	GElf_Shdr symhdr;
169*5bb525f4SRobert Mustacchi 	ulong_t nsyms;
170*5bb525f4SRobert Mustacchi 	int i;
171*5bb525f4SRobert Mustacchi 	const char *curfile = NULL;
172*5bb525f4SRobert Mustacchi 	int ret = 0;
173*5bb525f4SRobert Mustacchi 
174*5bb525f4SRobert Mustacchi 	while ((scn = elf_nextscn(elf, scn)) != NULL) {
175*5bb525f4SRobert Mustacchi 		if (gelf_getshdr(scn, &symhdr) == NULL) {
176*5bb525f4SRobert Mustacchi 			warnx("failed to get section header: %s",
177*5bb525f4SRobert Mustacchi 			    elf_errmsg(elf_errno()));
178*5bb525f4SRobert Mustacchi 			return (EXIT_FAILURE);
179*5bb525f4SRobert Mustacchi 		}
180*5bb525f4SRobert Mustacchi 
181*5bb525f4SRobert Mustacchi 		if (symhdr.sh_type == SHT_SYMTAB) {
182*5bb525f4SRobert Mustacchi 			symscn = scn;
183*5bb525f4SRobert Mustacchi 			break;
184*5bb525f4SRobert Mustacchi 		}
185*5bb525f4SRobert Mustacchi 	}
186*5bb525f4SRobert Mustacchi 
187*5bb525f4SRobert Mustacchi 	if (symscn == NULL) {
188*5bb525f4SRobert Mustacchi 		warnx("failed to find symbol table for %s", file);
189*5bb525f4SRobert Mustacchi 		return (EXIT_FAILURE);
190*5bb525f4SRobert Mustacchi 	}
191*5bb525f4SRobert Mustacchi 
192*5bb525f4SRobert Mustacchi 	if ((symdata = elf_getdata(symscn, NULL)) == NULL) {
193*5bb525f4SRobert Mustacchi 		warnx("failed to get data for symbol table %s: %s", file,
194*5bb525f4SRobert Mustacchi 		    elf_errmsg(elf_errno()));
195*5bb525f4SRobert Mustacchi 		return (EXIT_FAILURE);
196*5bb525f4SRobert Mustacchi 	}
197*5bb525f4SRobert Mustacchi 
198*5bb525f4SRobert Mustacchi 	if (symhdr.sh_link == SHN_XINDEX) {
199*5bb525f4SRobert Mustacchi 		warnx("test does not support extended ELF sections!");
200*5bb525f4SRobert Mustacchi 		return (EXIT_FAILURE);
201*5bb525f4SRobert Mustacchi 	}
202*5bb525f4SRobert Mustacchi 	nsyms = symhdr.sh_size / symhdr.sh_entsize;
203*5bb525f4SRobert Mustacchi 	if (nsyms > INT_MAX) {
204*5bb525f4SRobert Mustacchi 		warnx("file contains more symbols than libelf can iterate");
205*5bb525f4SRobert Mustacchi 		return (EXIT_FAILURE);
206*5bb525f4SRobert Mustacchi 	}
207*5bb525f4SRobert Mustacchi 
208*5bb525f4SRobert Mustacchi 	for (i = 1; i < (int)nsyms; i++) {
209*5bb525f4SRobert Mustacchi 		GElf_Sym sym;
210*5bb525f4SRobert Mustacchi 		const char *name;
211*5bb525f4SRobert Mustacchi 		uint_t type;
212*5bb525f4SRobert Mustacchi 
213*5bb525f4SRobert Mustacchi 		if (gelf_getsym(symdata, i, &sym) == NULL) {
214*5bb525f4SRobert Mustacchi 			warnx("failed to get data about symbol %d", i);
215*5bb525f4SRobert Mustacchi 			return (EXIT_FAILURE);
216*5bb525f4SRobert Mustacchi 		}
217*5bb525f4SRobert Mustacchi 
218*5bb525f4SRobert Mustacchi 		if ((name = elf_strptr(elf, symhdr.sh_link, sym.st_name)) ==
219*5bb525f4SRobert Mustacchi 		    NULL) {
220*5bb525f4SRobert Mustacchi 			warnx("failed to get name for symbol %d", i);
221*5bb525f4SRobert Mustacchi 			return (EXIT_FAILURE);
222*5bb525f4SRobert Mustacchi 		}
223*5bb525f4SRobert Mustacchi 
224*5bb525f4SRobert Mustacchi 		type = GELF_ST_TYPE(sym.st_info);
225*5bb525f4SRobert Mustacchi 		if (type == STT_FILE) {
226*5bb525f4SRobert Mustacchi 			curfile = name;
227*5bb525f4SRobert Mustacchi 			continue;
228*5bb525f4SRobert Mustacchi 		}
229*5bb525f4SRobert Mustacchi 
230*5bb525f4SRobert Mustacchi 		if (strcmp(name, "global") == 0) {
231*5bb525f4SRobert Mustacchi 			ret |= check_global(fp, &sym, i, curfile, name);
232*5bb525f4SRobert Mustacchi 		} else if (strcmp(name, "mumble") == 0) {
233*5bb525f4SRobert Mustacchi 			ret |= check_mumble(fp, &sym, i, curfile, name);
234*5bb525f4SRobert Mustacchi 		}
235*5bb525f4SRobert Mustacchi 	}
236*5bb525f4SRobert Mustacchi 
237*5bb525f4SRobert Mustacchi 	return (ret);
238*5bb525f4SRobert Mustacchi }
239*5bb525f4SRobert Mustacchi 
240*5bb525f4SRobert Mustacchi int
main(int argc,char * argv[])241*5bb525f4SRobert Mustacchi main(int argc, char *argv[])
242*5bb525f4SRobert Mustacchi {
243*5bb525f4SRobert Mustacchi 	int i, ret = 0;
244*5bb525f4SRobert Mustacchi 
245*5bb525f4SRobert Mustacchi 	if (argc < 2) {
246*5bb525f4SRobert Mustacchi 		errx(EXIT_FAILURE, "missing test files");
247*5bb525f4SRobert Mustacchi 	}
248*5bb525f4SRobert Mustacchi 
249*5bb525f4SRobert Mustacchi 	if (elf_version(EV_CURRENT) == EV_NONE) {
250*5bb525f4SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to initialize libelf");
251*5bb525f4SRobert Mustacchi 	}
252*5bb525f4SRobert Mustacchi 
253*5bb525f4SRobert Mustacchi 	for (i = 1; i < argc; i++) {
254*5bb525f4SRobert Mustacchi 		int fd;
255*5bb525f4SRobert Mustacchi 		ctf_file_t *fp;
256*5bb525f4SRobert Mustacchi 		Elf *elf;
257*5bb525f4SRobert Mustacchi 
258*5bb525f4SRobert Mustacchi 		if ((fd = open(argv[i], O_RDONLY)) < 0) {
259*5bb525f4SRobert Mustacchi 			warn("failed to open %s", argv[i]);
260*5bb525f4SRobert Mustacchi 			ret = EXIT_FAILURE;
261*5bb525f4SRobert Mustacchi 			continue;
262*5bb525f4SRobert Mustacchi 		}
263*5bb525f4SRobert Mustacchi 
264*5bb525f4SRobert Mustacchi 		if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
265*5bb525f4SRobert Mustacchi 			warnx("failed to open libelf handle to %s", argv[i]);
266*5bb525f4SRobert Mustacchi 			ret = EXIT_FAILURE;
267*5bb525f4SRobert Mustacchi 			(void) close(fd);
268*5bb525f4SRobert Mustacchi 			continue;
269*5bb525f4SRobert Mustacchi 		}
270*5bb525f4SRobert Mustacchi 
271*5bb525f4SRobert Mustacchi 		if ((fp = ctf_open(argv[i], &ret)) == NULL) {
272*5bb525f4SRobert Mustacchi 			warnx("failed to open %s: %s", argv[i],
273*5bb525f4SRobert Mustacchi 			    ctf_errmsg(ret));
274*5bb525f4SRobert Mustacchi 			ret = EXIT_FAILURE;
275*5bb525f4SRobert Mustacchi 			(void) close(fd);
276*5bb525f4SRobert Mustacchi 			(void) elf_end(elf);
277*5bb525f4SRobert Mustacchi 			continue;
278*5bb525f4SRobert Mustacchi 		}
279*5bb525f4SRobert Mustacchi 
280*5bb525f4SRobert Mustacchi 		if (check_merge_static(argv[i], fp, elf) != 0) {
281*5bb525f4SRobert Mustacchi 			ret = EXIT_FAILURE;
282*5bb525f4SRobert Mustacchi 		}
283*5bb525f4SRobert Mustacchi 
284*5bb525f4SRobert Mustacchi 		ctf_close(fp);
285*5bb525f4SRobert Mustacchi 		(void) close(fd);
286*5bb525f4SRobert Mustacchi 		(void) elf_end(elf);
287*5bb525f4SRobert Mustacchi 	}
288*5bb525f4SRobert Mustacchi 
289*5bb525f4SRobert Mustacchi 	return (ret);
290*5bb525f4SRobert Mustacchi }
291