Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/cddl/contrib/opensolaris/common/ctf/ctf_lookup.c
39507 views
1
/*
2
* CDDL HEADER START
3
*
4
* The contents of this file are subject to the terms of the
5
* Common Development and Distribution License, Version 1.0 only
6
* (the "License"). You may not use this file except in compliance
7
* with the License.
8
*
9
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10
* or http://www.opensolaris.org/os/licensing.
11
* See the License for the specific language governing permissions
12
* and limitations under the License.
13
*
14
* When distributing Covered Code, include this CDDL HEADER in each
15
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16
* If applicable, add the following below this CDDL HEADER, with the
17
* fields enclosed by brackets "[]" replaced with your own identifying
18
* information: Portions Copyright [yyyy] [name of copyright owner]
19
*
20
* CDDL HEADER END
21
*/
22
23
/*
24
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
25
* Use is subject to license terms.
26
*/
27
28
#pragma ident "%Z%%M% %I% %E% SMI"
29
30
#include <sys/sysmacros.h>
31
#include <ctf_impl.h>
32
33
/*
34
* Compare the given input string and length against a table of known C storage
35
* qualifier keywords. We just ignore these in ctf_lookup_by_name, below. To
36
* do this quickly, we use a pre-computed Perfect Hash Function similar to the
37
* technique originally described in the classic paper:
38
*
39
* R.J. Cichelli, "Minimal Perfect Hash Functions Made Simple",
40
* Communications of the ACM, Volume 23, Issue 1, January 1980, pp. 17-19.
41
*
42
* For an input string S of length N, we use hash H = S[N - 1] + N - 105, which
43
* for the current set of qualifiers yields a unique H in the range [0 .. 20].
44
* The hash can be modified when the keyword set changes as necessary. We also
45
* store the length of each keyword and check it prior to the final strcmp().
46
*/
47
static int
48
isqualifier(const char *s, size_t len)
49
{
50
static const struct qual {
51
const char *q_name;
52
size_t q_len;
53
} qhash[] = {
54
{ "static", 6 }, { "", 0 }, { "", 0 }, { "", 0 },
55
{ "volatile", 8 }, { "", 0 }, { "", 0 }, { "", 0 }, { "", 0 },
56
{ "", 0 }, { "auto", 4 }, { "extern", 6 }, { "", 0 }, { "", 0 },
57
{ "", 0 }, { "", 0 }, { "const", 5 }, { "register", 8 },
58
{ "", 0 }, { "restrict", 8 }, { "_Restrict", 9 }
59
};
60
61
int h = s[len - 1] + (int)len - 105;
62
const struct qual *qp;
63
64
if (h < 0 || h >= sizeof (qhash) / sizeof (qhash[0]))
65
return (0);
66
qp = &qhash[h];
67
return (len == qp->q_len && strncmp(qp->q_name, s, qp->q_len) == 0);
68
}
69
70
/*
71
* Attempt to convert the given C type name into the corresponding CTF type ID.
72
* It is not possible to do complete and proper conversion of type names
73
* without implementing a more full-fledged parser, which is necessary to
74
* handle things like types that are function pointers to functions that
75
* have arguments that are function pointers, and fun stuff like that.
76
* Instead, this function implements a very simple conversion algorithm that
77
* finds the things that we actually care about: structs, unions, enums,
78
* integers, floats, typedefs, and pointers to any of these named types.
79
*/
80
ctf_id_t
81
ctf_lookup_by_name(ctf_file_t *fp, const char *name)
82
{
83
static const char delimiters[] = " \t\n\r\v\f*";
84
85
const ctf_lookup_t *lp;
86
const ctf_helem_t *hp;
87
const char *p, *q, *end;
88
ctf_id_t type = 0;
89
ctf_id_t ntype, ptype;
90
91
if (name == NULL)
92
return (ctf_set_errno(fp, EINVAL));
93
94
for (p = name, end = name + strlen(name); *p != '\0'; p = q) {
95
while (isspace(*p))
96
p++; /* skip leading ws */
97
98
if (p == end)
99
break;
100
101
if ((q = strpbrk(p + 1, delimiters)) == NULL)
102
q = end; /* compare until end */
103
104
if (*p == '*') {
105
/*
106
* Find a pointer to type by looking in fp->ctf_ptrtab.
107
* If we can't find a pointer to the given type, see if
108
* we can compute a pointer to the type resulting from
109
* resolving the type down to its base type and use
110
* that instead. This helps with cases where the CTF
111
* data includes "struct foo *" but not "foo_t *" and
112
* the user tries to access "foo_t *" in the debugger.
113
*/
114
ntype = fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX(fp, type)];
115
if (ntype == 0) {
116
ntype = ctf_type_resolve(fp, type);
117
if (ntype == CTF_ERR || (ntype = fp->ctf_ptrtab[
118
LCTF_TYPE_TO_INDEX(fp, ntype)]) == 0) {
119
(void) ctf_set_errno(fp, ECTF_NOTYPE);
120
goto err;
121
}
122
}
123
124
type = LCTF_INDEX_TO_TYPE(fp, ntype,
125
(fp->ctf_flags & LCTF_CHILD));
126
127
q = p + 1;
128
continue;
129
}
130
131
if (isqualifier(p, (size_t)(q - p)))
132
continue; /* skip qualifier keyword */
133
134
for (lp = fp->ctf_lookups; lp->ctl_prefix != NULL; lp++) {
135
if (lp->ctl_prefix[0] == '\0' ||
136
((size_t)(q - p) >= lp->ctl_len && strncmp(p,
137
lp->ctl_prefix, (size_t)(q - p)) == 0)) {
138
for (p += lp->ctl_len; isspace(*p); p++)
139
continue; /* skip prefix and next ws */
140
141
if ((q = strchr(p, '*')) == NULL)
142
q = end; /* compare until end */
143
144
while (isspace(q[-1]))
145
q--; /* exclude trailing ws */
146
147
if ((hp = ctf_hash_lookup(lp->ctl_hash, fp, p,
148
(size_t)(q - p))) == NULL) {
149
(void) ctf_set_errno(fp, ECTF_NOTYPE);
150
goto err;
151
}
152
153
type = hp->h_type;
154
break;
155
}
156
}
157
158
if (lp->ctl_prefix == NULL) {
159
(void) ctf_set_errno(fp, ECTF_NOTYPE);
160
goto err;
161
}
162
}
163
164
if (*p != '\0' || type == 0)
165
return (ctf_set_errno(fp, ECTF_SYNTAX));
166
167
return (type);
168
169
err:
170
if (fp->ctf_parent != NULL &&
171
(ptype = ctf_lookup_by_name(fp->ctf_parent, name)) != CTF_ERR)
172
return (ptype);
173
174
return (CTF_ERR);
175
}
176
177
/*
178
* Given a symbol table index, return the type of the data object described
179
* by the corresponding entry in the symbol table.
180
*/
181
ctf_id_t
182
ctf_lookup_by_symbol(ctf_file_t *fp, ulong_t symidx)
183
{
184
const ctf_sect_t *sp = &fp->ctf_symtab;
185
ctf_id_t type;
186
187
if (sp->cts_data == NULL)
188
return (ctf_set_errno(fp, ECTF_NOSYMTAB));
189
190
if (symidx >= fp->ctf_nsyms)
191
return (ctf_set_errno(fp, EINVAL));
192
193
if (sp->cts_entsize == sizeof (Elf32_Sym)) {
194
const Elf32_Sym *symp = (Elf32_Sym *)sp->cts_data + symidx;
195
if (ELF32_ST_TYPE(symp->st_info) != STT_OBJECT)
196
return (ctf_set_errno(fp, ECTF_NOTDATA));
197
} else {
198
const Elf64_Sym *symp = (Elf64_Sym *)sp->cts_data + symidx;
199
if (ELF64_ST_TYPE(symp->st_info) != STT_OBJECT)
200
return (ctf_set_errno(fp, ECTF_NOTDATA));
201
}
202
203
if (fp->ctf_sxlate[symidx] == -1u)
204
return (ctf_set_errno(fp, ECTF_NOTYPEDAT));
205
206
type = *(uint_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[symidx]);
207
if (type == 0)
208
return (ctf_set_errno(fp, ECTF_NOTYPEDAT));
209
210
return (type);
211
}
212
213
/*
214
* Return the pointer to the internal CTF type data corresponding to the
215
* given type ID. If the ID is invalid, the function returns NULL.
216
* This function is not exported outside of the library.
217
*/
218
const void *
219
ctf_lookup_by_id(ctf_file_t **fpp, ctf_id_t type)
220
{
221
ctf_file_t *fp = *fpp; /* caller passes in starting CTF container */
222
223
if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT(fp, type)) {
224
if (fp->ctf_parent == NULL) {
225
(void) ctf_set_errno(*fpp, ECTF_NOPARENT);
226
return (NULL);
227
}
228
229
/* The parent may be using a different CTF version. */
230
type = LCTF_TYPE_TO_INDEX(fp, type);
231
fp = fp->ctf_parent;
232
} else {
233
type = LCTF_TYPE_TO_INDEX(fp, type);
234
}
235
236
if (type > 0 && type <= fp->ctf_typemax) {
237
*fpp = fp; /* function returns ending CTF container */
238
return (LCTF_INDEX_TO_TYPEPTR(fp, type));
239
}
240
241
(void) ctf_set_errno(fp, ECTF_BADID);
242
return (NULL);
243
}
244
245
/*
246
* Given a symbol table index, return the info for the function described
247
* by the corresponding entry in the symbol table.
248
*/
249
int
250
ctf_func_info(ctf_file_t *fp, ulong_t symidx, ctf_funcinfo_t *fip)
251
{
252
const ctf_sect_t *sp = &fp->ctf_symtab;
253
const uint_t *dp;
254
uint_t info, kind, n;
255
256
if (sp->cts_data == NULL)
257
return (ctf_set_errno(fp, ECTF_NOSYMTAB));
258
259
if (symidx >= fp->ctf_nsyms)
260
return (ctf_set_errno(fp, EINVAL));
261
262
if (sp->cts_entsize == sizeof (Elf32_Sym)) {
263
const Elf32_Sym *symp = (Elf32_Sym *)sp->cts_data + symidx;
264
if (ELF32_ST_TYPE(symp->st_info) != STT_FUNC)
265
return (ctf_set_errno(fp, ECTF_NOTFUNC));
266
} else {
267
const Elf64_Sym *symp = (Elf64_Sym *)sp->cts_data + symidx;
268
if (ELF64_ST_TYPE(symp->st_info) != STT_FUNC)
269
return (ctf_set_errno(fp, ECTF_NOTFUNC));
270
}
271
272
if (fp->ctf_sxlate[symidx] == -1u)
273
return (ctf_set_errno(fp, ECTF_NOFUNCDAT));
274
275
dp = (uint_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[symidx]);
276
277
info = *dp++;
278
kind = LCTF_INFO_KIND(fp, info);
279
n = LCTF_INFO_VLEN(fp, info);
280
281
if (kind == CTF_K_UNKNOWN && n == 0)
282
return (ctf_set_errno(fp, ECTF_NOFUNCDAT));
283
284
if (kind != CTF_K_FUNCTION)
285
return (ctf_set_errno(fp, ECTF_CORRUPT));
286
287
fip->ctc_return = *dp++;
288
fip->ctc_argc = n;
289
fip->ctc_flags = 0;
290
291
if (n != 0 && dp[n - 1] == 0) {
292
fip->ctc_flags |= CTF_FUNC_VARARG;
293
fip->ctc_argc--;
294
}
295
296
return (0);
297
}
298
299
/*
300
* Given a symbol table index, return the arguments for the function described
301
* by the corresponding entry in the symbol table.
302
*/
303
int
304
ctf_func_args(ctf_file_t *fp, ulong_t symidx, uint_t argc, ctf_id_t *argv)
305
{
306
const uint_t *dp;
307
ctf_funcinfo_t f;
308
309
if (ctf_func_info(fp, symidx, &f) == CTF_ERR)
310
return (CTF_ERR); /* errno is set for us */
311
312
/*
313
* The argument data is two uint_t's past the translation table
314
* offset: one for the function info, and one for the return type.
315
*/
316
dp = (uint_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[symidx]) + 2;
317
318
for (argc = MIN(argc, f.ctc_argc); argc != 0; argc--)
319
*argv++ = *dp++;
320
321
return (0);
322
}
323
324