forked from namhyung/uftrace
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsymbol-libelf.c
130 lines (101 loc) · 2.45 KB
/
symbol-libelf.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#ifdef HAVE_LIBELF
#include <fcntl.h>
#include <gelf.h>
#include <unistd.h>
/* This should be defined before #include "utils.h" */
#define PR_FMT "symbol"
#define PR_DOMAIN DBG_SYMBOL
#include "utils/dwarf.h"
#include "utils/symbol-libelf.h"
#include "utils/utils.h"
int elf_init(const char *filename, struct uftrace_elf_data *elf)
{
/* it will be set only in elf_retry() */
elf->dwfl = NULL;
elf->fd = open(filename, O_RDONLY);
if (elf->fd < 0) {
pr_dbg("error during open ELF file: %s: %m\n", filename);
goto err;
}
elf_version(EV_CURRENT);
elf->handle = elf_begin(elf->fd, ELF_C_READ_MMAP, NULL);
if (elf->handle == NULL)
goto err_close;
if (gelf_getehdr(elf->handle, &elf->ehdr) == NULL)
goto err_end;
return 0;
err_end:
elf_end(elf->handle);
err_close:
pr_dbg("ELF error when loading symbols: %s\n", elf_errmsg(elf_errno()));
close(elf->fd);
elf->fd = -1;
err:
elf->handle = NULL;
return -1;
}
void elf_finish(struct uftrace_elf_data *elf)
{
if (elf->fd < 0)
return;
#ifdef HAVE_LIBDW
if (elf->dwfl) {
/* it'll close ELF handle and FD */
dwfl_end(elf->dwfl);
return;
}
#endif
elf_end(elf->handle);
elf->handle = NULL;
close(elf->fd);
elf->fd = -1;
}
/* return 1 if it wants to retry with libdwfl, 0 otherwise */
int elf_retry(const char *filename, struct uftrace_elf_data *elf)
{
#ifdef HAVE_LIBDW
Dwfl *dwfl;
Dwfl_Module *mod;
Dwarf_Addr bias;
Dwarf *dw;
/* it already tried (and failed), no retry */
if (elf->dwfl)
return 0;
dwfl = dwfl_begin(&dwfl_callbacks);
if (dwfl == NULL) {
pr_dbg("dwfl_begin() failed\n");
return 0;
}
mod = dwfl_report_offline(dwfl, filename, filename, elf->fd);
if (mod == NULL) {
pr_dbg("cannot report file: %s\n", dwfl_errmsg(dwfl_errno()));
goto out;
}
dw = dwfl_module_getdwarf(mod, &bias);
if (dw == NULL) {
pr_dbg("cannot find debug file: %s\n", dwfl_errmsg(dwfl_errno()));
goto out;
}
/* invalidate the existing ELF */
elf_end(elf->handle);
/* update the ELF handle from the (separate) debug file */
elf->handle = dwarf_getelf(dw);
if (elf->handle) {
elf->dwfl = dwfl;
return 1;
}
out:
dwfl_end(dwfl);
#endif
return 0;
}
void elf_get_secdata(struct uftrace_elf_data *elf, struct uftrace_elf_iter *iter)
{
iter->data = elf_getdata((iter)->scn, NULL);
}
void elf_read_secdata(struct uftrace_elf_data *elf, struct uftrace_elf_iter *iter, unsigned offset,
void *buf, size_t len)
{
memcpy(buf, iter->data->d_buf + offset, len);
}
#endif /* HAVE_LIBELF */