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