Skip to content

Commit b691f64

Browse files
Namhyung Kimacmel
authored andcommitted
perf symbols: Implement poor man's ELF parser
Implement a minimal elf parser for getting build-id. It assumes that required elf.h header is provided by libc header on the system and the parser only looks for PT_NOTE program header to check build-id. Signed-off-by: Namhyung Kim <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Paul Mackerras <[email protected]> Cc: Peter Zijlstra <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 393be2e commit b691f64

File tree

1 file changed

+235
-7
lines changed

1 file changed

+235
-7
lines changed

tools/perf/util/symbol-minimal.c

Lines changed: 235 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,71 @@
11
#include "symbol.h"
22

3+
#include <elf.h>
4+
#include <stdio.h>
5+
#include <fcntl.h>
6+
#include <string.h>
7+
#include <byteswap.h>
8+
#include <sys/stat.h>
39

4-
int filename__read_build_id(const char *filename __used, void *bf __used,
5-
size_t size __used)
10+
11+
static bool check_need_swap(int file_endian)
612
{
7-
return -1;
13+
const int data = 1;
14+
u8 *check = (u8 *)&data;
15+
int host_endian;
16+
17+
if (check[0] == 1)
18+
host_endian = ELFDATA2LSB;
19+
else
20+
host_endian = ELFDATA2MSB;
21+
22+
return host_endian != file_endian;
823
}
924

10-
int sysfs__read_build_id(const char *filename __used, void *build_id __used,
11-
size_t size __used)
25+
#define NOTE_ALIGN(sz) (((sz) + 3) & ~3)
26+
27+
#define NT_GNU_BUILD_ID 3
28+
29+
static int read_build_id(void *note_data, size_t note_len, void *bf,
30+
size_t size, bool need_swap)
1231
{
32+
struct {
33+
u32 n_namesz;
34+
u32 n_descsz;
35+
u32 n_type;
36+
} *nhdr;
37+
void *ptr;
38+
39+
ptr = note_data;
40+
while (ptr < (note_data + note_len)) {
41+
const char *name;
42+
size_t namesz, descsz;
43+
44+
nhdr = ptr;
45+
if (need_swap) {
46+
nhdr->n_namesz = bswap_32(nhdr->n_namesz);
47+
nhdr->n_descsz = bswap_32(nhdr->n_descsz);
48+
nhdr->n_type = bswap_32(nhdr->n_type);
49+
}
50+
51+
namesz = NOTE_ALIGN(nhdr->n_namesz);
52+
descsz = NOTE_ALIGN(nhdr->n_descsz);
53+
54+
ptr += sizeof(*nhdr);
55+
name = ptr;
56+
ptr += namesz;
57+
if (nhdr->n_type == NT_GNU_BUILD_ID &&
58+
nhdr->n_namesz == sizeof("GNU")) {
59+
if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
60+
size_t sz = min(size, descsz);
61+
memcpy(bf, ptr, sz);
62+
memset(bf + sz, 0, size - sz);
63+
return 0;
64+
}
65+
}
66+
ptr += descsz;
67+
}
68+
1369
return -1;
1470
}
1571

@@ -19,18 +75,190 @@ int filename__read_debuglink(const char *filename __used,
1975
return -1;
2076
}
2177

78+
/*
79+
* Just try PT_NOTE header otherwise fails
80+
*/
81+
int filename__read_build_id(const char *filename, void *bf, size_t size)
82+
{
83+
FILE *fp;
84+
int ret = -1;
85+
bool need_swap = false;
86+
u8 e_ident[EI_NIDENT];
87+
size_t buf_size;
88+
void *buf;
89+
int i;
90+
91+
fp = fopen(filename, "r");
92+
if (fp == NULL)
93+
return -1;
94+
95+
if (fread(e_ident, sizeof(e_ident), 1, fp) != 1)
96+
goto out;
97+
98+
if (memcmp(e_ident, ELFMAG, SELFMAG) ||
99+
e_ident[EI_VERSION] != EV_CURRENT)
100+
goto out;
101+
102+
need_swap = check_need_swap(e_ident[EI_DATA]);
103+
104+
/* for simplicity */
105+
fseek(fp, 0, SEEK_SET);
106+
107+
if (e_ident[EI_CLASS] == ELFCLASS32) {
108+
Elf32_Ehdr ehdr;
109+
Elf32_Phdr *phdr;
110+
111+
if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1)
112+
goto out;
113+
114+
if (need_swap) {
115+
ehdr.e_phoff = bswap_32(ehdr.e_phoff);
116+
ehdr.e_phentsize = bswap_16(ehdr.e_phentsize);
117+
ehdr.e_phnum = bswap_16(ehdr.e_phnum);
118+
}
119+
120+
buf_size = ehdr.e_phentsize * ehdr.e_phnum;
121+
buf = malloc(buf_size);
122+
if (buf == NULL)
123+
goto out;
124+
125+
fseek(fp, ehdr.e_phoff, SEEK_SET);
126+
if (fread(buf, buf_size, 1, fp) != 1)
127+
goto out_free;
128+
129+
for (i = 0, phdr = buf; i < ehdr.e_phnum; i++, phdr++) {
130+
void *tmp;
131+
132+
if (need_swap) {
133+
phdr->p_type = bswap_32(phdr->p_type);
134+
phdr->p_offset = bswap_32(phdr->p_offset);
135+
phdr->p_filesz = bswap_32(phdr->p_filesz);
136+
}
137+
138+
if (phdr->p_type != PT_NOTE)
139+
continue;
140+
141+
buf_size = phdr->p_filesz;
142+
tmp = realloc(buf, buf_size);
143+
if (tmp == NULL)
144+
goto out_free;
145+
146+
buf = tmp;
147+
fseek(fp, phdr->p_offset, SEEK_SET);
148+
if (fread(buf, buf_size, 1, fp) != 1)
149+
goto out_free;
150+
151+
ret = read_build_id(buf, buf_size, bf, size, need_swap);
152+
if (ret == 0)
153+
ret = size;
154+
break;
155+
}
156+
} else {
157+
Elf64_Ehdr ehdr;
158+
Elf64_Phdr *phdr;
159+
160+
if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1)
161+
goto out;
162+
163+
if (need_swap) {
164+
ehdr.e_phoff = bswap_64(ehdr.e_phoff);
165+
ehdr.e_phentsize = bswap_16(ehdr.e_phentsize);
166+
ehdr.e_phnum = bswap_16(ehdr.e_phnum);
167+
}
168+
169+
buf_size = ehdr.e_phentsize * ehdr.e_phnum;
170+
buf = malloc(buf_size);
171+
if (buf == NULL)
172+
goto out;
173+
174+
fseek(fp, ehdr.e_phoff, SEEK_SET);
175+
if (fread(buf, buf_size, 1, fp) != 1)
176+
goto out_free;
177+
178+
for (i = 0, phdr = buf; i < ehdr.e_phnum; i++, phdr++) {
179+
void *tmp;
180+
181+
if (need_swap) {
182+
phdr->p_type = bswap_32(phdr->p_type);
183+
phdr->p_offset = bswap_64(phdr->p_offset);
184+
phdr->p_filesz = bswap_64(phdr->p_filesz);
185+
}
186+
187+
if (phdr->p_type != PT_NOTE)
188+
continue;
189+
190+
buf_size = phdr->p_filesz;
191+
tmp = realloc(buf, buf_size);
192+
if (tmp == NULL)
193+
goto out_free;
194+
195+
buf = tmp;
196+
fseek(fp, phdr->p_offset, SEEK_SET);
197+
if (fread(buf, buf_size, 1, fp) != 1)
198+
goto out_free;
199+
200+
ret = read_build_id(buf, buf_size, bf, size, need_swap);
201+
if (ret == 0)
202+
ret = size;
203+
break;
204+
}
205+
}
206+
out_free:
207+
free(buf);
208+
out:
209+
fclose(fp);
210+
return ret;
211+
}
212+
213+
int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
214+
{
215+
int fd;
216+
int ret = -1;
217+
struct stat stbuf;
218+
size_t buf_size;
219+
void *buf;
220+
221+
fd = open(filename, O_RDONLY);
222+
if (fd < 0)
223+
return -1;
224+
225+
if (fstat(fd, &stbuf) < 0)
226+
goto out;
227+
228+
buf_size = stbuf.st_size;
229+
buf = malloc(buf_size);
230+
if (buf == NULL)
231+
goto out;
232+
233+
if (read(fd, buf, buf_size) != (ssize_t) buf_size)
234+
goto out_free;
235+
236+
ret = read_build_id(buf, buf_size, build_id, size, false);
237+
out_free:
238+
free(buf);
239+
out:
240+
close(fd);
241+
return ret;
242+
}
243+
22244
int dso__synthesize_plt_symbols(struct dso *dso __used, char *name __used,
23245
struct map *map __used,
24246
symbol_filter_t filter __used)
25247
{
26248
return 0;
27249
}
28250

29-
int dso__load_sym(struct dso *dso __used, struct map *map __used,
30-
const char *name __used, int fd __used,
251+
int dso__load_sym(struct dso *dso, struct map *map __used,
252+
const char *name, int fd __used,
31253
symbol_filter_t filter __used, int kmodule __used,
32254
int want_symtab __used)
33255
{
256+
unsigned char *build_id[BUILD_ID_SIZE];
257+
258+
if (filename__read_build_id(name, build_id, BUILD_ID_SIZE) > 0) {
259+
dso__set_build_id(dso, build_id);
260+
return 1;
261+
}
34262
return 0;
35263
}
36264

0 commit comments

Comments
 (0)