Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/cddl/contrib/opensolaris/cmd/lockstat/sym.c
39488 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
* Copyright (c) 1997-1999 by Sun Microsystems, Inc.
24
* All rights reserved.
25
*/
26
27
#pragma ident "%Z%%M% %I% %E% SMI"
28
29
#include <stdio.h>
30
#include <fcntl.h>
31
#include <ctype.h>
32
#include <string.h>
33
#include <signal.h>
34
#include <errno.h>
35
#include <stdlib.h>
36
#include <stdarg.h>
37
#include <unistd.h>
38
#include <limits.h>
39
#include <sys/types.h>
40
#include <sys/stat.h>
41
42
#include <libelf.h>
43
#include <link.h>
44
#include <elf.h>
45
#include <gelf.h>
46
#ifdef illumos
47
#include <sys/machelf.h>
48
49
#include <kstat.h>
50
#else
51
#include <sys/elf.h>
52
#include <sys/param.h>
53
#include <sys/module.h>
54
#include <sys/linker.h>
55
#endif
56
#include <sys/cpuvar.h>
57
58
typedef struct syment {
59
uintptr_t addr;
60
char *name;
61
size_t size;
62
} syment_t;
63
64
static syment_t *symbol_table;
65
static int nsyms, maxsyms;
66
static char maxsymname[64];
67
68
#ifdef illumos
69
#ifdef _ELF64
70
#define elf_getshdr elf64_getshdr
71
#else
72
#define elf_getshdr elf32_getshdr
73
#endif
74
#endif
75
76
static void
77
add_symbol(char *name, uintptr_t addr, size_t size)
78
{
79
syment_t *sep;
80
81
if (nsyms >= maxsyms) {
82
maxsyms += 10000;
83
symbol_table = realloc(symbol_table, maxsyms * sizeof (*sep));
84
if (symbol_table == NULL) {
85
(void) fprintf(stderr, "can't allocate symbol table\n");
86
exit(3);
87
}
88
}
89
sep = &symbol_table[nsyms++];
90
91
sep->name = name;
92
sep->addr = addr;
93
sep->size = size;
94
}
95
96
static void
97
remove_symbol(uintptr_t addr)
98
{
99
int i;
100
syment_t *sep = symbol_table;
101
102
for (i = 0; i < nsyms; i++, sep++)
103
if (sep->addr == addr)
104
sep->addr = 0;
105
}
106
107
#ifdef illumos
108
static void
109
fake_up_certain_popular_kernel_symbols(void)
110
{
111
kstat_ctl_t *kc;
112
kstat_t *ksp;
113
char *name;
114
115
if ((kc = kstat_open()) == NULL)
116
return;
117
118
for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
119
if (strcmp(ksp->ks_module, "cpu_info") == 0) {
120
if ((name = malloc(20)) == NULL)
121
break;
122
/*
123
* For consistency, keep cpu[0] and toss cpu0
124
* or any other such symbols.
125
*/
126
if (ksp->ks_instance == 0)
127
remove_symbol((uintptr_t)ksp->ks_private);
128
(void) sprintf(name, "cpu[%d]", ksp->ks_instance);
129
add_symbol(name, (uintptr_t)ksp->ks_private,
130
sizeof (struct cpu));
131
}
132
}
133
(void) kstat_close(kc);
134
}
135
#else /* !illumos */
136
static void
137
fake_up_certain_popular_kernel_symbols(void)
138
{
139
char *name;
140
uintptr_t addr;
141
int i;
142
143
/* Good for up to 256 CPUs */
144
for(i=0; i < 256; i++) {
145
if ((name = malloc(20)) == NULL)
146
break;
147
(void) sprintf(name, "cpu[%d]", i);
148
addr = 0x01000000 + (i << 16);
149
add_symbol(name, addr, sizeof (uintptr_t));
150
}
151
}
152
#endif /* illumos */
153
154
static int
155
symcmp(const void *p1, const void *p2)
156
{
157
uintptr_t a1 = ((syment_t *)p1)->addr;
158
uintptr_t a2 = ((syment_t *)p2)->addr;
159
160
if (a1 < a2)
161
return (-1);
162
if (a1 > a2)
163
return (1);
164
return (0);
165
}
166
167
int
168
symtab_init(void)
169
{
170
Elf *elf;
171
Elf_Scn *scn = NULL;
172
GElf_Sym *symtab, *symp, *lastsym;
173
char *strtab;
174
uint_t cnt;
175
int fd;
176
int i;
177
int strindex = -1;
178
179
#ifndef illumos
180
if ((fd = open("/dev/ksyms", O_RDONLY)) == -1) {
181
if (errno == ENOENT && modfind("ksyms") == -1) {
182
kldload("ksyms");
183
fd = open("/dev/ksyms", O_RDONLY);
184
}
185
if (fd == -1)
186
return (-1);
187
}
188
#else
189
if ((fd = open("/dev/ksyms", O_RDONLY)) == -1)
190
return (-1);
191
#endif
192
193
(void) elf_version(EV_CURRENT);
194
195
elf = elf_begin(fd, ELF_C_READ, NULL);
196
for (cnt = 1; (scn = elf_nextscn(elf, scn)) != NULL; cnt++) {
197
GElf_Shdr shdr;
198
(void) gelf_getshdr(scn, &shdr);
199
if (shdr.sh_type == SHT_SYMTAB) {
200
symtab = (GElf_Sym *)elf_getdata(scn, NULL)->d_buf;
201
nsyms = shdr.sh_size / shdr.sh_entsize;
202
strindex = shdr.sh_link;
203
}
204
}
205
206
for (cnt = 1; (scn = elf_nextscn(elf, scn)) != NULL; cnt++) {
207
if (cnt == strindex)
208
strtab = (char *)elf_getdata(scn, NULL)->d_buf;
209
}
210
211
lastsym = symtab + nsyms;
212
nsyms = 0;
213
for (symp = symtab; symp < lastsym; symp++)
214
if ((uint_t)ELF32_ST_TYPE(symp->st_info) <= STT_FUNC &&
215
symp->st_size != 0)
216
add_symbol(symp->st_name + strtab,
217
(uintptr_t)symp->st_value, (size_t)symp->st_size);
218
219
fake_up_certain_popular_kernel_symbols();
220
(void) sprintf(maxsymname, "0x%lx", ULONG_MAX);
221
add_symbol(maxsymname, ULONG_MAX, 1);
222
223
qsort(symbol_table, nsyms, sizeof (syment_t), symcmp);
224
225
/*
226
* Destroy all duplicate symbols, then sort it again.
227
*/
228
for (i = 0; i < nsyms - 1; i++)
229
if (symbol_table[i].addr == symbol_table[i + 1].addr)
230
symbol_table[i].addr = 0;
231
232
qsort(symbol_table, nsyms, sizeof (syment_t), symcmp);
233
234
while (symbol_table[1].addr == 0) {
235
symbol_table++;
236
nsyms--;
237
}
238
symbol_table[0].name = "(usermode)";
239
symbol_table[0].addr = 0;
240
symbol_table[0].size = 1;
241
242
close(fd);
243
return (0);
244
}
245
246
char *
247
addr_to_sym(uintptr_t addr, uintptr_t *offset, size_t *sizep)
248
{
249
int lo = 0;
250
int hi = nsyms - 1;
251
int mid;
252
syment_t *sep;
253
254
while (hi - lo > 1) {
255
mid = (lo + hi) / 2;
256
if (addr >= symbol_table[mid].addr) {
257
lo = mid;
258
} else {
259
hi = mid;
260
}
261
}
262
sep = &symbol_table[lo];
263
*offset = addr - sep->addr;
264
*sizep = sep->size;
265
return (sep->name);
266
}
267
268
uintptr_t
269
sym_to_addr(char *name)
270
{
271
int i;
272
syment_t *sep = symbol_table;
273
274
for (i = 0; i < nsyms; i++) {
275
if (strcmp(name, sep->name) == 0)
276
return (sep->addr);
277
sep++;
278
}
279
return (0);
280
}
281
282
size_t
283
sym_size(char *name)
284
{
285
int i;
286
syment_t *sep = symbol_table;
287
288
for (i = 0; i < nsyms; i++) {
289
if (strcmp(name, sep->name) == 0)
290
return (sep->size);
291
sep++;
292
}
293
return (0);
294
}
295
296