xref: /dragonfly/games/hangman/getsym.c (revision 6a3cbbc2)
1 /*	$OpenBSD: ksyms.c,v 1.8 2015/02/07 03:26:20 tedu Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Miodrag Vallat.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <unistd.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <string.h>
24 
25 #include <sys/exec.h>
26 #include <sys/elf64.h>
27 
28 #include "hangman.h"
29 
30 typedef Elf64_Ehdr Elf_Ehdr;
31 typedef Elf64_Shdr Elf_Shdr;
32 
33 static int ksyms_elf_parse(void);
34 
35 void
36 sym_getword(void)
37 {
38 	uint tries;
39 	off_t pos;
40 	int buflen;
41 	char symbuf[1 + BUFSIZ], *sym, *end;
42 	size_t symlen;
43 
44 	for (tries = 0; tries < MAXBADWORDS; tries++) {
45 		pos = arc4random_uniform(symsize);
46 		if (lseek(symfd, pos + symoffs, SEEK_SET) == -1)
47 			continue;
48 		buflen = read(symfd, symbuf, BUFSIZ);
49 		if (buflen < 0)
50 			continue;
51 
52 		/*
53 		 * The buffer is hopefully large enough to hold at least
54 		 * a complete symbol, i.e. two occurences of NUL, or
55 		 * one occurence of NUL and the buffer containing the end
56 		 * of the string table. We make sure the buffer will be
57 		 * NUL terminated in all cases.
58 		 */
59 		if (buflen + pos >= symsize)
60 			buflen = symsize - pos;
61 		*(end = symbuf + buflen) = '\0';
62 
63 		for (sym = symbuf; *sym != '\0'; sym++)
64 			;
65 		if (sym == end)
66 			continue;
67 
68 		symlen = strlen(++sym);
69 		if (symlen < MINLEN || symlen > MAXLEN)
70 			continue;
71 
72 		/* ignore symbols containing dots or dollar signs */
73 		if (strchr(sym, '.') != NULL || strchr(sym, '$') != NULL)
74 			continue;
75 
76 		break;
77 	}
78 
79 	if (tries >= MAXBADWORDS) {
80 		mvcur(0, COLS - 1, LINES -1, 0);
81 		endwin();
82 		errx(1, "can't seem a suitable symbol in %s",
83 		    Dict_name);
84 	}
85 
86 	strlcpy(Word, sym, sizeof(Word));
87 	strlcpy(Known, sym, sizeof(Known));
88 	for (sym = Known; *sym != '\0'; sym++) {
89 		if (*sym == '-')
90 			*sym = '_';	/* try not to confuse player */
91 		if (isalnum((unsigned char)*sym))
92 			*sym = '-';
93 	}
94 }
95 
96 int
97 sym_setup(void)
98 {
99 	if ((symfd = open(Dict_name, O_RDONLY)) < 0)
100 		return -1;
101 
102 	if (ksyms_elf_parse() == 0)
103 		return 0;
104 
105 	close(symfd);
106 	errno = ENOEXEC;
107 	return -1;
108 }
109 
110 int
111 ksyms_elf_parse(void)
112 {
113 	Elf_Ehdr eh;
114 	Elf_Shdr sh;
115 	uint s;
116 
117 	if (lseek(symfd, 0, SEEK_SET) == -1)
118 		return -1;
119 
120 	if (read(symfd, &eh, sizeof(eh)) != sizeof(eh))
121 		return -1;
122 
123 	if (!IS_ELF(eh))
124 		return -1;
125 
126 	if (lseek(symfd, eh.e_shoff, SEEK_SET) == -1)
127 		return -1;
128 
129 	symoffs = 0;
130 	symsize = 0;
131 
132 	for (s = 0; s < eh.e_shnum; s++) {
133 		if (read(symfd, &sh, sizeof(sh)) != sizeof(sh))
134 			return -1;
135 
136 		/*
137 		 * There should be two string table sections, one with the
138 		 * name of the sections themselves, and one with the symbol
139 		 * names. Just pick the largest one.
140 		 */
141 		if (sh.sh_type == SHT_STRTAB) {
142 			if (symsize > (off_t)sh.sh_size)
143 				continue;
144 
145 			symoffs = (off_t)sh.sh_offset;
146 			symsize = (off_t)sh.sh_size;
147 		}
148 	}
149 
150 	if (symsize == 0)
151 		return -1;
152 
153 	return 0;
154 }
155