Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/cddl/contrib/opensolaris/tools/ctf/cvt/input.c
39586 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 (the "License").
6
* You may not use this file except in compliance with the License.
7
*
8
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9
* or http://www.opensolaris.org/os/licensing.
10
* See the License for the specific language governing permissions
11
* and limitations under the License.
12
*
13
* When distributing Covered Code, include this CDDL HEADER in each
14
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15
* If applicable, add the following below this CDDL HEADER, with the
16
* fields enclosed by brackets "[]" replaced with your own identifying
17
* information: Portions Copyright [yyyy] [name of copyright owner]
18
*
19
* CDDL HEADER END
20
*/
21
/*
22
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23
* Use is subject to license terms.
24
*/
25
26
#pragma ident "%Z%%M% %I% %E% SMI"
27
28
/*
29
* Routines for retrieving CTF data from a .SUNW_ctf ELF section
30
*/
31
32
#include <stdio.h>
33
#include <stdlib.h>
34
#include <fcntl.h>
35
#include <unistd.h>
36
#include <gelf.h>
37
#include <strings.h>
38
#include <sys/types.h>
39
40
#include "ctftools.h"
41
#include "memory.h"
42
#include "symbol.h"
43
44
typedef int read_cb_f(tdata_t *, char *, void *);
45
46
/*
47
* Return the source types that the object was generated from.
48
*/
49
source_types_t
50
built_source_types(Elf *elf, char const *file)
51
{
52
source_types_t types = SOURCE_NONE;
53
symit_data_t *si;
54
55
if ((si = symit_new(elf, file)) == NULL)
56
return (SOURCE_NONE);
57
58
while (symit_next(si, STT_FILE) != NULL) {
59
char *name = symit_name(si);
60
size_t len = strlen(name);
61
if (len < 2 || name[len - 2] != '.') {
62
types |= SOURCE_UNKNOWN;
63
continue;
64
}
65
66
switch (name[len - 1]) {
67
case 'c':
68
types |= SOURCE_C;
69
break;
70
case 'h':
71
/* ignore */
72
break;
73
case 's':
74
case 'S':
75
types |= SOURCE_S;
76
break;
77
default:
78
types |= SOURCE_UNKNOWN;
79
}
80
}
81
82
symit_free(si);
83
return (types);
84
}
85
86
static int
87
read_file(Elf *elf, char *file, char *label, read_cb_f *func, void *arg,
88
int require_ctf)
89
{
90
Elf_Scn *ctfscn;
91
Elf_Data *ctfdata = NULL;
92
symit_data_t *si = NULL;
93
int ctfscnidx;
94
tdata_t *td;
95
96
if ((ctfscnidx = findelfsecidx(elf, file, ".SUNW_ctf")) < 0) {
97
if (require_ctf &&
98
(built_source_types(elf, file) & SOURCE_C)) {
99
terminate("Input file %s was partially built from "
100
"C sources, but no CTF data was present\n", file);
101
}
102
return (0);
103
}
104
105
if ((ctfscn = elf_getscn(elf, ctfscnidx)) == NULL ||
106
(ctfdata = elf_getdata(ctfscn, NULL)) == NULL)
107
elfterminate(file, "Cannot read CTF section");
108
109
/* Reconstruction of type tree */
110
if ((si = symit_new(elf, file)) == NULL) {
111
warning("%s has no symbol table - skipping", file);
112
return (0);
113
}
114
115
td = ctf_load(file, ctfdata->d_buf, ctfdata->d_size, si, label);
116
tdata_build_hashes(td);
117
118
symit_free(si);
119
120
if (td != NULL) {
121
if (func(td, file, arg) < 0)
122
return (-1);
123
else
124
return (1);
125
}
126
return (0);
127
}
128
129
static int
130
read_archive(int fd, Elf *elf, char *file, char *label, read_cb_f *func,
131
void *arg, int require_ctf)
132
{
133
Elf *melf;
134
Elf_Cmd cmd = ELF_C_READ;
135
Elf_Arhdr *arh;
136
int secnum = 1, found = 0;
137
138
while ((melf = elf_begin(fd, cmd, elf)) != NULL) {
139
int rc = 0;
140
141
if ((arh = elf_getarhdr(melf)) == NULL) {
142
elfterminate(file, "Can't get archive header for "
143
"member %d", secnum);
144
}
145
146
/* skip special sections - their names begin with "/" */
147
if (*arh->ar_name != '/') {
148
size_t memlen = strlen(file) + 1 +
149
strlen(arh->ar_name) + 1 + 1;
150
char *memname = xmalloc(memlen);
151
152
snprintf(memname, memlen, "%s(%s)", file, arh->ar_name);
153
154
switch (elf_kind(melf)) {
155
case ELF_K_AR:
156
rc = read_archive(fd, melf, memname, label,
157
func, arg, require_ctf);
158
break;
159
case ELF_K_ELF:
160
rc = read_file(melf, memname, label,
161
func, arg, require_ctf);
162
break;
163
default:
164
terminate("%s: Unknown elf kind %d\n",
165
memname, elf_kind(melf));
166
}
167
168
free(memname);
169
}
170
171
cmd = elf_next(melf);
172
(void) elf_end(melf);
173
secnum++;
174
175
if (rc < 0)
176
return (rc);
177
else
178
found += rc;
179
}
180
181
return (found);
182
}
183
184
static int
185
read_ctf_common(char *file, char *label, read_cb_f *func, void *arg,
186
int require_ctf)
187
{
188
Elf *elf;
189
int found = 0;
190
int fd;
191
192
debug(3, "Reading %s (label %s)\n", file, (label ? label : "NONE"));
193
194
(void) elf_version(EV_CURRENT);
195
196
if ((fd = open(file, O_RDONLY)) < 0)
197
terminate("%s: Cannot open for reading", file);
198
if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
199
elfterminate(file, "Cannot read");
200
201
switch (elf_kind(elf)) {
202
case ELF_K_AR:
203
found = read_archive(fd, elf, file, label,
204
func, arg, require_ctf);
205
break;
206
207
case ELF_K_ELF:
208
found = read_file(elf, file, label,
209
func, arg, require_ctf);
210
break;
211
212
default:
213
terminate("%s: Unknown elf kind %d\n", file, elf_kind(elf));
214
}
215
216
(void) elf_end(elf);
217
(void) close(fd);
218
219
return (found);
220
}
221
222
/*ARGSUSED*/
223
int
224
read_ctf_save_cb(tdata_t *td, char *name __unused, void *retp)
225
{
226
tdata_t **tdp = retp;
227
228
*tdp = td;
229
230
return (1);
231
}
232
233
int
234
read_ctf(char **files, int n, char *label, read_cb_f *func, void *private,
235
int require_ctf)
236
{
237
int found;
238
int i, rc;
239
240
for (i = 0, found = 0; i < n; i++) {
241
if ((rc = read_ctf_common(files[i], label, func,
242
private, require_ctf)) < 0)
243
return (rc);
244
found += rc;
245
}
246
247
return (found);
248
}
249
250
static int
251
count_archive(int fd, Elf *elf, char *file)
252
{
253
Elf *melf;
254
Elf_Cmd cmd = ELF_C_READ;
255
Elf_Arhdr *arh;
256
int nfiles = 0, err = 0;
257
258
while ((melf = elf_begin(fd, cmd, elf)) != NULL) {
259
if ((arh = elf_getarhdr(melf)) == NULL) {
260
warning("Can't process input archive %s\n",
261
file);
262
err++;
263
}
264
265
if (*arh->ar_name != '/')
266
nfiles++;
267
268
cmd = elf_next(melf);
269
(void) elf_end(melf);
270
}
271
272
if (err > 0)
273
return (-1);
274
275
return (nfiles);
276
}
277
278
int
279
count_files(char **files, int n)
280
{
281
int nfiles = 0, err = 0;
282
Elf *elf;
283
int fd, rc, i;
284
285
(void) elf_version(EV_CURRENT);
286
287
for (i = 0; i < n; i++) {
288
char *file = files[i];
289
290
if ((fd = open(file, O_RDONLY)) < 0) {
291
warning("Can't read input file %s", file);
292
err++;
293
continue;
294
}
295
296
if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
297
warning("Can't open input file %s: %s\n", file,
298
elf_errmsg(-1));
299
err++;
300
(void) close(fd);
301
continue;
302
}
303
304
switch (elf_kind(elf)) {
305
case ELF_K_AR:
306
if ((rc = count_archive(fd, elf, file)) < 0)
307
err++;
308
else
309
nfiles += rc;
310
break;
311
case ELF_K_ELF:
312
nfiles++;
313
break;
314
default:
315
warning("Input file %s is corrupt\n", file);
316
err++;
317
}
318
319
(void) elf_end(elf);
320
(void) close(fd);
321
}
322
323
if (err > 0)
324
return (-1);
325
326
debug(2, "Found %d files in %d input files\n", nfiles, n);
327
328
return (nfiles);
329
}
330
331
struct symit_data {
332
GElf_Shdr si_shdr;
333
Elf_Data *si_symd;
334
Elf_Data *si_strd;
335
GElf_Sym si_cursym;
336
char *si_curname;
337
char *si_curfile;
338
int si_nument;
339
int si_next;
340
};
341
342
symit_data_t *
343
symit_new(Elf *elf, const char *file)
344
{
345
symit_data_t *si;
346
Elf_Scn *scn;
347
int symtabidx;
348
349
if ((symtabidx = findelfsecidx(elf, file, ".symtab")) < 0)
350
return (NULL);
351
352
si = xcalloc(sizeof (symit_data_t));
353
354
if ((scn = elf_getscn(elf, symtabidx)) == NULL ||
355
gelf_getshdr(scn, &si->si_shdr) == NULL ||
356
(si->si_symd = elf_getdata(scn, NULL)) == NULL)
357
elfterminate(file, "Cannot read .symtab");
358
359
if ((scn = elf_getscn(elf, si->si_shdr.sh_link)) == NULL ||
360
(si->si_strd = elf_getdata(scn, NULL)) == NULL)
361
elfterminate(file, "Cannot read strings for .symtab");
362
363
si->si_nument = si->si_shdr.sh_size / si->si_shdr.sh_entsize;
364
365
return (si);
366
}
367
368
void
369
symit_free(symit_data_t *si)
370
{
371
free(si);
372
}
373
374
void
375
symit_reset(symit_data_t *si)
376
{
377
si->si_next = 0;
378
}
379
380
char *
381
symit_curfile(symit_data_t *si)
382
{
383
return (si->si_curfile);
384
}
385
386
GElf_Sym *
387
symit_next(symit_data_t *si, int type)
388
{
389
GElf_Sym sym;
390
char *bname;
391
int check_sym = (type == STT_OBJECT || type == STT_FUNC);
392
393
for (; si->si_next < si->si_nument; si->si_next++) {
394
gelf_getsym(si->si_symd, si->si_next, &si->si_cursym);
395
gelf_getsym(si->si_symd, si->si_next, &sym);
396
si->si_curname = (caddr_t)si->si_strd->d_buf + sym.st_name;
397
398
if (GELF_ST_TYPE(sym.st_info) == STT_FILE) {
399
bname = strrchr(si->si_curname, '/');
400
si->si_curfile = bname == NULL ? si->si_curname : bname + 1;
401
}
402
403
if (GELF_ST_TYPE(sym.st_info) != type ||
404
sym.st_shndx == SHN_UNDEF)
405
continue;
406
407
if (check_sym && ignore_symbol(&sym, si->si_curname))
408
continue;
409
410
si->si_next++;
411
412
return (&si->si_cursym);
413
}
414
415
return (NULL);
416
}
417
418
char *
419
symit_name(symit_data_t *si)
420
{
421
return (si->si_curname);
422
}
423
424