diff options
author | Masami Hiramatsu <mhiramat@redhat.com> | 2010-02-25 08:35:42 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-02-25 11:49:29 -0500 |
commit | 804b36068eccd8163ccea420c662fb5d1a21b141 (patch) | |
tree | 08837b6d7be24d56c30af2932e59fa1c23420396 /tools/perf | |
parent | 81cb8aa327b5923b38eccc795c8b7170be20b9ff (diff) |
perf probe: Use elfutils-libdw for analyzing debuginfo
Newer gcc introduces newer & richer debuginfo, and only libdw
in elfutils project can support it. So perf probe moves onto
elfutils-libdw from libdwarf.
Changes in v3:
- Cast Dwarf_Addr/Dwarf_Word to uintmax_t for printf-formats.
- Recover a sign-prefix which was removed in v2 by mistake.
Changes in v2:
- Fix a type-casting bug in Makefile.
- Cast Dwarf_Addr/Dwarf_Word to unsigned long long for printf-formats.
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: K.Prasad <prasad@linux.vnet.ibm.com>
Cc: Ulrich Drepper <drepper@redhat.com>
Cc: Roland McGrath <roland@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
LKML-Reference: <20100225133542.6725.34724.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Makefile | 10 | ||||
-rw-r--r-- | tools/perf/builtin-probe.c | 22 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 696 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.h | 52 |
4 files changed, 314 insertions, 466 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 54a5b50ff312..2d537382c686 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -500,12 +500,12 @@ else | |||
500 | msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); | 500 | msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); |
501 | endif | 501 | endif |
502 | 502 | ||
503 | ifneq ($(shell sh -c "(echo '\#ifndef _MIPS_SZLONG'; echo '\#define _MIPS_SZLONG 0'; echo '\#endif'; echo '\#include <dwarf.h>'; echo '\#include <libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/libdwarf -ldwarf -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) | 503 | ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) |
504 | msg := $(warning No libdwarf.h found or old libdwarf.h found, disables dwarf support. Please install libdwarf-dev/libdwarf-devel >= 20081231); | 504 | msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev); |
505 | BASIC_CFLAGS += -DNO_LIBDWARF | 505 | BASIC_CFLAGS += -DNO_DWARF_SUPPORT |
506 | else | 506 | else |
507 | BASIC_CFLAGS += -I/usr/include/libdwarf | 507 | BASIC_CFLAGS += -I/usr/include/elfutils |
508 | EXTLIBS += -lelf -ldwarf | 508 | EXTLIBS += -lelf -ldw |
509 | LIB_OBJS += util/probe-finder.o | 509 | LIB_OBJS += util/probe-finder.o |
510 | endif | 510 | endif |
511 | 511 | ||
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index c3e61194f4c6..d8d3f0525895 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -128,7 +128,7 @@ static void evaluate_probe_point(struct probe_point *pp) | |||
128 | pp->function); | 128 | pp->function); |
129 | } | 129 | } |
130 | 130 | ||
131 | #ifndef NO_LIBDWARF | 131 | #ifndef NO_DWARF_SUPPORT |
132 | static int open_vmlinux(void) | 132 | static int open_vmlinux(void) |
133 | { | 133 | { |
134 | if (map__load(session.kmaps[MAP__FUNCTION], NULL) < 0) { | 134 | if (map__load(session.kmaps[MAP__FUNCTION], NULL) < 0) { |
@@ -156,7 +156,7 @@ static const char * const probe_usage[] = { | |||
156 | "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", | 156 | "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", |
157 | "perf probe [<options>] --del '[GROUP:]EVENT' ...", | 157 | "perf probe [<options>] --del '[GROUP:]EVENT' ...", |
158 | "perf probe --list", | 158 | "perf probe --list", |
159 | #ifndef NO_LIBDWARF | 159 | #ifndef NO_DWARF_SUPPORT |
160 | "perf probe --line 'LINEDESC'", | 160 | "perf probe --line 'LINEDESC'", |
161 | #endif | 161 | #endif |
162 | NULL | 162 | NULL |
@@ -165,7 +165,7 @@ static const char * const probe_usage[] = { | |||
165 | static const struct option options[] = { | 165 | static const struct option options[] = { |
166 | OPT_BOOLEAN('v', "verbose", &verbose, | 166 | OPT_BOOLEAN('v', "verbose", &verbose, |
167 | "be more verbose (show parsed arguments, etc)"), | 167 | "be more verbose (show parsed arguments, etc)"), |
168 | #ifndef NO_LIBDWARF | 168 | #ifndef NO_DWARF_SUPPORT |
169 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 169 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
170 | "file", "vmlinux pathname"), | 170 | "file", "vmlinux pathname"), |
171 | #endif | 171 | #endif |
@@ -174,7 +174,7 @@ static const struct option options[] = { | |||
174 | OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", | 174 | OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", |
175 | opt_del_probe_event), | 175 | opt_del_probe_event), |
176 | OPT_CALLBACK('a', "add", NULL, | 176 | OPT_CALLBACK('a', "add", NULL, |
177 | #ifdef NO_LIBDWARF | 177 | #ifdef NO_DWARF_SUPPORT |
178 | "[EVENT=]FUNC[+OFFS|%return] [ARG ...]", | 178 | "[EVENT=]FUNC[+OFFS|%return] [ARG ...]", |
179 | #else | 179 | #else |
180 | "[EVENT=]FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]", | 180 | "[EVENT=]FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]", |
@@ -185,7 +185,7 @@ static const struct option options[] = { | |||
185 | "\t\tFUNC:\tFunction name\n" | 185 | "\t\tFUNC:\tFunction name\n" |
186 | "\t\tOFFS:\tOffset from function entry (in byte)\n" | 186 | "\t\tOFFS:\tOffset from function entry (in byte)\n" |
187 | "\t\t%return:\tPut the probe at function return\n" | 187 | "\t\t%return:\tPut the probe at function return\n" |
188 | #ifdef NO_LIBDWARF | 188 | #ifdef NO_DWARF_SUPPORT |
189 | "\t\tARG:\tProbe argument (only \n" | 189 | "\t\tARG:\tProbe argument (only \n" |
190 | #else | 190 | #else |
191 | "\t\tSRC:\tSource code path\n" | 191 | "\t\tSRC:\tSource code path\n" |
@@ -197,7 +197,7 @@ static const struct option options[] = { | |||
197 | opt_add_probe_event), | 197 | opt_add_probe_event), |
198 | OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events" | 198 | OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events" |
199 | " with existing name"), | 199 | " with existing name"), |
200 | #ifndef NO_LIBDWARF | 200 | #ifndef NO_DWARF_SUPPORT |
201 | OPT_CALLBACK('L', "line", NULL, | 201 | OPT_CALLBACK('L', "line", NULL, |
202 | "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]", | 202 | "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]", |
203 | "Show source code lines.", opt_show_lines), | 203 | "Show source code lines.", opt_show_lines), |
@@ -225,7 +225,7 @@ static void init_vmlinux(void) | |||
225 | int cmd_probe(int argc, const char **argv, const char *prefix __used) | 225 | int cmd_probe(int argc, const char **argv, const char *prefix __used) |
226 | { | 226 | { |
227 | int i, ret; | 227 | int i, ret; |
228 | #ifndef NO_LIBDWARF | 228 | #ifndef NO_DWARF_SUPPORT |
229 | int fd; | 229 | int fd; |
230 | #endif | 230 | #endif |
231 | struct probe_point *pp; | 231 | struct probe_point *pp; |
@@ -261,7 +261,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
261 | return 0; | 261 | return 0; |
262 | } | 262 | } |
263 | 263 | ||
264 | #ifndef NO_LIBDWARF | 264 | #ifndef NO_DWARF_SUPPORT |
265 | if (session.show_lines) { | 265 | if (session.show_lines) { |
266 | if (session.nr_probe != 0 || session.dellist) { | 266 | if (session.nr_probe != 0 || session.dellist) { |
267 | pr_warning(" Error: Don't use --line with" | 267 | pr_warning(" Error: Don't use --line with" |
@@ -292,9 +292,9 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
292 | init_vmlinux(); | 292 | init_vmlinux(); |
293 | 293 | ||
294 | if (session.need_dwarf) | 294 | if (session.need_dwarf) |
295 | #ifdef NO_LIBDWARF | 295 | #ifdef NO_DWARF_SUPPORT |
296 | die("Debuginfo-analysis is not supported"); | 296 | die("Debuginfo-analysis is not supported"); |
297 | #else /* !NO_LIBDWARF */ | 297 | #else /* !NO_DWARF_SUPPORT */ |
298 | pr_debug("Some probes require debuginfo.\n"); | 298 | pr_debug("Some probes require debuginfo.\n"); |
299 | 299 | ||
300 | fd = open_vmlinux(); | 300 | fd = open_vmlinux(); |
@@ -335,7 +335,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
335 | close(fd); | 335 | close(fd); |
336 | 336 | ||
337 | end_dwarf: | 337 | end_dwarf: |
338 | #endif /* !NO_LIBDWARF */ | 338 | #endif /* !NO_DWARF_SUPPORT */ |
339 | 339 | ||
340 | /* Synthesize probes without dwarf */ | 340 | /* Synthesize probes without dwarf */ |
341 | for (i = 0; i < session.nr_probe; i++) { | 341 | for (i = 0; i < session.nr_probe; i++) { |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index c819fd59da9e..c422472fe4d1 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -44,8 +44,6 @@ struct die_link { | |||
44 | Dwarf_Die die; /* Current die */ | 44 | Dwarf_Die die; /* Current die */ |
45 | }; | 45 | }; |
46 | 46 | ||
47 | static Dwarf_Debug __dw_debug; | ||
48 | static Dwarf_Error __dw_error; | ||
49 | 47 | ||
50 | /* | 48 | /* |
51 | * Generic dwarf analysis helpers | 49 | * Generic dwarf analysis helpers |
@@ -114,157 +112,114 @@ static int strtailcmp(const char *s1, const char *s2) | |||
114 | } | 112 | } |
115 | 113 | ||
116 | /* Find the fileno of the target file. */ | 114 | /* Find the fileno of the target file. */ |
117 | static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname) | 115 | static int cu_find_fileno(Dwarf_Die *cu_die, const char *fname) |
118 | { | 116 | { |
119 | Dwarf_Signed cnt, i; | 117 | Dwarf_Files *files; |
120 | Dwarf_Unsigned found = 0; | 118 | size_t nfiles, i; |
121 | char **srcs; | 119 | const char *src; |
122 | int ret; | 120 | int ret; |
123 | 121 | ||
124 | if (!fname) | 122 | if (!fname) |
125 | return 0; | 123 | return -EINVAL; |
126 | 124 | ||
127 | ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error); | 125 | ret = dwarf_getsrcfiles(cu_die, &files, &nfiles); |
128 | if (ret == DW_DLV_OK) { | 126 | if (ret == 0) { |
129 | for (i = 0; i < cnt && !found; i++) { | 127 | for (i = 0; i < nfiles; i++) { |
130 | if (strtailcmp(srcs[i], fname) == 0) | 128 | src = dwarf_filesrc(files, i, NULL, NULL); |
131 | found = i + 1; | 129 | if (strtailcmp(src, fname) == 0) { |
132 | dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); | 130 | ret = (int)i; /*???: +1 or not?*/ |
131 | break; | ||
132 | } | ||
133 | } | 133 | } |
134 | for (; i < cnt; i++) | 134 | if (ret) |
135 | dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); | 135 | pr_debug("found fno: %d\n", ret); |
136 | dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST); | ||
137 | } | 136 | } |
138 | if (found) | 137 | return ret; |
139 | pr_debug("found fno: %d\n", (int)found); | ||
140 | return found; | ||
141 | } | 138 | } |
142 | 139 | ||
143 | static int cu_get_filename(Dwarf_Die cu_die, Dwarf_Unsigned fno, char **buf) | 140 | struct __addr_die_search_param { |
141 | Dwarf_Addr addr; | ||
142 | Dwarf_Die *die_mem; | ||
143 | }; | ||
144 | |||
145 | static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) | ||
144 | { | 146 | { |
145 | Dwarf_Signed cnt, i; | 147 | struct __addr_die_search_param *ad = data; |
146 | char **srcs; | ||
147 | int ret = 0; | ||
148 | 148 | ||
149 | if (!buf || !fno) | 149 | if (dwarf_tag(fn_die) == DW_TAG_subprogram && |
150 | return -EINVAL; | 150 | dwarf_haspc(fn_die, ad->addr)) { |
151 | memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); | ||
152 | return DWARF_CB_ABORT; | ||
153 | } | ||
154 | return DWARF_CB_OK; | ||
155 | } | ||
151 | 156 | ||
152 | ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error); | 157 | /* Search a real subprogram including this line, */ |
153 | if (ret == DW_DLV_OK) { | 158 | static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr, |
154 | if ((Dwarf_Unsigned)cnt > fno - 1) { | 159 | Dwarf_Die *die_mem) |
155 | *buf = strdup(srcs[fno - 1]); | 160 | { |
156 | ret = 0; | 161 | struct __addr_die_search_param ad; |
157 | pr_debug("found filename: %s\n", *buf); | 162 | ad.addr = addr; |
158 | } else | 163 | ad.die_mem = die_mem; |
159 | ret = -ENOENT; | 164 | /* dwarf_getscopes can't find subprogram. */ |
160 | for (i = 0; i < cnt; i++) | 165 | if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0)) |
161 | dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); | 166 | return NULL; |
162 | dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST); | 167 | else |
163 | } else | 168 | return die_mem; |
164 | ret = -EINVAL; | ||
165 | return ret; | ||
166 | } | 169 | } |
167 | 170 | ||
168 | /* Compare diename and tname */ | 171 | /* Compare diename and tname */ |
169 | static int die_compare_name(Dwarf_Die dw_die, const char *tname) | 172 | static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) |
170 | { | 173 | { |
171 | char *name; | 174 | const char *name; |
172 | int ret; | 175 | name = dwarf_diename(dw_die); |
173 | ret = dwarf_diename(dw_die, &name, &__dw_error); | 176 | DIE_IF(name == NULL); |
174 | DIE_IF(ret == DW_DLV_ERROR); | 177 | return strcmp(tname, name); |
175 | if (ret == DW_DLV_OK) { | ||
176 | ret = strcmp(tname, name); | ||
177 | dwarf_dealloc(__dw_debug, name, DW_DLA_STRING); | ||
178 | } else | ||
179 | ret = -1; | ||
180 | return ret; | ||
181 | } | 178 | } |
182 | 179 | ||
183 | /* Check the address is in the subprogram(function). */ | 180 | /* Check the address is in the subprogram(function). */ |
184 | static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr, | 181 | static bool die_within_subprogram(Dwarf_Die *sp_die, Dwarf_Addr addr, |
185 | Dwarf_Signed *offs) | 182 | size_t *offs) |
186 | { | 183 | { |
187 | Dwarf_Addr lopc, hipc; | 184 | Dwarf_Addr epc; |
188 | int ret; | 185 | int ret; |
189 | 186 | ||
190 | /* TODO: check ranges */ | 187 | ret = dwarf_haspc(sp_die, addr); |
191 | ret = dwarf_lowpc(sp_die, &lopc, &__dw_error); | 188 | if (ret <= 0) |
192 | DIE_IF(ret == DW_DLV_ERROR); | 189 | return false; |
193 | if (ret == DW_DLV_NO_ENTRY) | ||
194 | return 0; | ||
195 | ret = dwarf_highpc(sp_die, &hipc, &__dw_error); | ||
196 | DIE_IF(ret != DW_DLV_OK); | ||
197 | if (lopc <= addr && addr < hipc) { | ||
198 | *offs = addr - lopc; | ||
199 | return 1; | ||
200 | } else | ||
201 | return 0; | ||
202 | } | ||
203 | 190 | ||
204 | /* Check the die is inlined function */ | 191 | if (offs) { |
205 | static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die) | 192 | ret = dwarf_entrypc(sp_die, &epc); |
206 | { | 193 | DIE_IF(ret == -1); |
207 | /* TODO: check strictly */ | 194 | *offs = addr - epc; |
208 | Dwarf_Bool inl; | 195 | } |
209 | int ret; | ||
210 | 196 | ||
211 | ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error); | 197 | return true; |
212 | DIE_IF(ret == DW_DLV_ERROR); | ||
213 | return inl; | ||
214 | } | 198 | } |
215 | 199 | ||
216 | /* Get the offset of abstruct_origin */ | 200 | /* Get entry pc(or low pc, 1st entry of ranges) of the die */ |
217 | static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die) | 201 | static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die) |
218 | { | 202 | { |
219 | Dwarf_Attribute attr; | 203 | Dwarf_Addr epc; |
220 | Dwarf_Off cu_offs; | ||
221 | int ret; | 204 | int ret; |
222 | 205 | ||
223 | ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error); | 206 | ret = dwarf_entrypc(dw_die, &epc); |
224 | DIE_IF(ret != DW_DLV_OK); | 207 | DIE_IF(ret == -1); |
225 | ret = dwarf_formref(attr, &cu_offs, &__dw_error); | 208 | return epc; |
226 | DIE_IF(ret != DW_DLV_OK); | ||
227 | dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); | ||
228 | return cu_offs; | ||
229 | } | 209 | } |
230 | 210 | ||
231 | /* Get entry pc(or low pc, 1st entry of ranges) of the die */ | 211 | /* Check if the abstract origin's address or not */ |
232 | static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die) | 212 | static bool die_compare_abstract_origin(Dwarf_Die *in_die, void *origin_addr) |
233 | { | 213 | { |
234 | Dwarf_Attribute attr; | 214 | Dwarf_Attribute attr; |
235 | Dwarf_Addr addr; | 215 | Dwarf_Die origin; |
236 | Dwarf_Off offs; | ||
237 | Dwarf_Ranges *ranges; | ||
238 | Dwarf_Signed cnt; | ||
239 | int ret; | ||
240 | 216 | ||
241 | /* Try to get entry pc */ | 217 | if (!dwarf_attr(in_die, DW_AT_abstract_origin, &attr)) |
242 | ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error); | 218 | return false; |
243 | DIE_IF(ret == DW_DLV_ERROR); | 219 | if (!dwarf_formref_die(&attr, &origin)) |
244 | if (ret == DW_DLV_OK) { | 220 | return false; |
245 | ret = dwarf_formaddr(attr, &addr, &__dw_error); | ||
246 | DIE_IF(ret != DW_DLV_OK); | ||
247 | dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); | ||
248 | return addr; | ||
249 | } | ||
250 | 221 | ||
251 | /* Try to get low pc */ | 222 | return origin.addr == origin_addr; |
252 | ret = dwarf_lowpc(dw_die, &addr, &__dw_error); | ||
253 | DIE_IF(ret == DW_DLV_ERROR); | ||
254 | if (ret == DW_DLV_OK) | ||
255 | return addr; | ||
256 | |||
257 | /* Try to get ranges */ | ||
258 | ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error); | ||
259 | DIE_IF(ret != DW_DLV_OK); | ||
260 | ret = dwarf_formref(attr, &offs, &__dw_error); | ||
261 | DIE_IF(ret != DW_DLV_OK); | ||
262 | ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL, | ||
263 | &__dw_error); | ||
264 | DIE_IF(ret != DW_DLV_OK); | ||
265 | addr = ranges[0].dwr_addr1; | ||
266 | dwarf_ranges_dealloc(__dw_debug, ranges, cnt); | ||
267 | return addr; | ||
268 | } | 223 | } |
269 | 224 | ||
270 | /* | 225 | /* |
@@ -275,7 +230,6 @@ static int __search_die_tree(struct die_link *cur_link, | |||
275 | int (*die_cb)(struct die_link *, void *), | 230 | int (*die_cb)(struct die_link *, void *), |
276 | void *data) | 231 | void *data) |
277 | { | 232 | { |
278 | Dwarf_Die new_die; | ||
279 | struct die_link new_link; | 233 | struct die_link new_link; |
280 | int ret; | 234 | int ret; |
281 | 235 | ||
@@ -285,31 +239,24 @@ static int __search_die_tree(struct die_link *cur_link, | |||
285 | /* Check current die */ | 239 | /* Check current die */ |
286 | while (!(ret = die_cb(cur_link, data))) { | 240 | while (!(ret = die_cb(cur_link, data))) { |
287 | /* Check child die */ | 241 | /* Check child die */ |
288 | ret = dwarf_child(cur_link->die, &new_die, &__dw_error); | 242 | ret = dwarf_child(&cur_link->die, &new_link.die); |
289 | DIE_IF(ret == DW_DLV_ERROR); | 243 | if (ret == 0) { |
290 | if (ret == DW_DLV_OK) { | ||
291 | new_link.parent = cur_link; | 244 | new_link.parent = cur_link; |
292 | new_link.die = new_die; | ||
293 | ret = __search_die_tree(&new_link, die_cb, data); | 245 | ret = __search_die_tree(&new_link, die_cb, data); |
294 | if (ret) | 246 | if (ret) |
295 | break; | 247 | break; |
296 | } | 248 | } |
297 | 249 | ||
298 | /* Move to next sibling */ | 250 | /* Move to next sibling */ |
299 | ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die, | 251 | ret = dwarf_siblingof(&cur_link->die, &cur_link->die); |
300 | &__dw_error); | 252 | if (ret != 0) |
301 | DIE_IF(ret == DW_DLV_ERROR); | ||
302 | dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE); | ||
303 | cur_link->die = new_die; | ||
304 | if (ret == DW_DLV_NO_ENTRY) | ||
305 | return 0; | 253 | return 0; |
306 | } | 254 | } |
307 | dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE); | ||
308 | return ret; | 255 | return ret; |
309 | } | 256 | } |
310 | 257 | ||
311 | /* Search a die in its children's die tree */ | 258 | /* Search a die in its children's die tree */ |
312 | static int search_die_from_children(Dwarf_Die parent_die, | 259 | static int search_die_from_children(Dwarf_Die *parent_die, |
313 | int (*die_cb)(struct die_link *, void *), | 260 | int (*die_cb)(struct die_link *, void *), |
314 | void *data) | 261 | void *data) |
315 | { | 262 | { |
@@ -317,125 +264,58 @@ static int search_die_from_children(Dwarf_Die parent_die, | |||
317 | int ret; | 264 | int ret; |
318 | 265 | ||
319 | new_link.parent = NULL; | 266 | new_link.parent = NULL; |
320 | ret = dwarf_child(parent_die, &new_link.die, &__dw_error); | 267 | ret = dwarf_child(parent_die, &new_link.die); |
321 | DIE_IF(ret == DW_DLV_ERROR); | 268 | if (ret == 0) |
322 | if (ret == DW_DLV_OK) | ||
323 | return __search_die_tree(&new_link, die_cb, data); | 269 | return __search_die_tree(&new_link, die_cb, data); |
324 | else | 270 | else |
325 | return 0; | 271 | return 0; |
326 | } | 272 | } |
327 | 273 | ||
328 | /* Find a locdesc corresponding to the address */ | ||
329 | static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc, | ||
330 | Dwarf_Addr addr) | ||
331 | { | ||
332 | Dwarf_Signed lcnt; | ||
333 | Dwarf_Locdesc **llbuf; | ||
334 | int ret, i; | ||
335 | |||
336 | ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error); | ||
337 | DIE_IF(ret != DW_DLV_OK); | ||
338 | ret = DW_DLV_NO_ENTRY; | ||
339 | for (i = 0; i < lcnt; ++i) { | ||
340 | if (llbuf[i]->ld_lopc <= addr && | ||
341 | llbuf[i]->ld_hipc > addr) { | ||
342 | memcpy(desc, llbuf[i], sizeof(Dwarf_Locdesc)); | ||
343 | desc->ld_s = | ||
344 | malloc(sizeof(Dwarf_Loc) * llbuf[i]->ld_cents); | ||
345 | DIE_IF(desc->ld_s == NULL); | ||
346 | memcpy(desc->ld_s, llbuf[i]->ld_s, | ||
347 | sizeof(Dwarf_Loc) * llbuf[i]->ld_cents); | ||
348 | ret = DW_DLV_OK; | ||
349 | break; | ||
350 | } | ||
351 | dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK); | ||
352 | dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC); | ||
353 | } | ||
354 | /* Releasing loop */ | ||
355 | for (; i < lcnt; ++i) { | ||
356 | dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK); | ||
357 | dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC); | ||
358 | } | ||
359 | dwarf_dealloc(__dw_debug, llbuf, DW_DLA_LIST); | ||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | /* Get decl_file attribute value (file number) */ | ||
364 | static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die) | ||
365 | { | ||
366 | Dwarf_Attribute attr; | ||
367 | Dwarf_Unsigned fno; | ||
368 | int ret; | ||
369 | |||
370 | ret = dwarf_attr(sp_die, DW_AT_decl_file, &attr, &__dw_error); | ||
371 | DIE_IF(ret != DW_DLV_OK); | ||
372 | dwarf_formudata(attr, &fno, &__dw_error); | ||
373 | DIE_IF(ret != DW_DLV_OK); | ||
374 | dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); | ||
375 | return fno; | ||
376 | } | ||
377 | |||
378 | /* Get decl_line attribute value (line number) */ | ||
379 | static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die) | ||
380 | { | ||
381 | Dwarf_Attribute attr; | ||
382 | Dwarf_Unsigned lno; | ||
383 | int ret; | ||
384 | |||
385 | ret = dwarf_attr(sp_die, DW_AT_decl_line, &attr, &__dw_error); | ||
386 | DIE_IF(ret != DW_DLV_OK); | ||
387 | dwarf_formudata(attr, &lno, &__dw_error); | ||
388 | DIE_IF(ret != DW_DLV_OK); | ||
389 | dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); | ||
390 | return lno; | ||
391 | } | ||
392 | 274 | ||
393 | /* | 275 | /* |
394 | * Probe finder related functions | 276 | * Probe finder related functions |
395 | */ | 277 | */ |
396 | 278 | ||
397 | /* Show a location */ | 279 | /* Show a location */ |
398 | static void show_location(Dwarf_Loc *loc, struct probe_finder *pf) | 280 | static void show_location(Dwarf_Op *op, struct probe_finder *pf) |
399 | { | 281 | { |
400 | Dwarf_Small op; | 282 | unsigned int regn; |
401 | Dwarf_Unsigned regn; | 283 | Dwarf_Word offs = 0; |
402 | Dwarf_Signed offs; | ||
403 | int deref = 0, ret; | 284 | int deref = 0, ret; |
404 | const char *regs; | 285 | const char *regs; |
405 | 286 | ||
406 | op = loc->lr_atom; | 287 | /* TODO: support CFA */ |
407 | |||
408 | /* If this is based on frame buffer, set the offset */ | 288 | /* If this is based on frame buffer, set the offset */ |
409 | if (op == DW_OP_fbreg) { | 289 | if (op->atom == DW_OP_fbreg) { |
290 | if (pf->fb_ops == NULL) | ||
291 | die("The attribute of frame base is not supported.\n"); | ||
410 | deref = 1; | 292 | deref = 1; |
411 | offs = (Dwarf_Signed)loc->lr_number; | 293 | offs = op->number; |
412 | op = pf->fbloc.ld_s[0].lr_atom; | 294 | op = &pf->fb_ops[0]; |
413 | loc = &pf->fbloc.ld_s[0]; | 295 | } |
414 | } else | ||
415 | offs = 0; | ||
416 | 296 | ||
417 | if (op >= DW_OP_breg0 && op <= DW_OP_breg31) { | 297 | if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { |
418 | regn = op - DW_OP_breg0; | 298 | regn = op->atom - DW_OP_breg0; |
419 | offs += (Dwarf_Signed)loc->lr_number; | 299 | offs += op->number; |
420 | deref = 1; | 300 | deref = 1; |
421 | } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) { | 301 | } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { |
422 | regn = op - DW_OP_reg0; | 302 | regn = op->atom - DW_OP_reg0; |
423 | } else if (op == DW_OP_bregx) { | 303 | } else if (op->atom == DW_OP_bregx) { |
424 | regn = loc->lr_number; | 304 | regn = op->number; |
425 | offs += (Dwarf_Signed)loc->lr_number2; | 305 | offs += op->number2; |
426 | deref = 1; | 306 | deref = 1; |
427 | } else if (op == DW_OP_regx) { | 307 | } else if (op->atom == DW_OP_regx) { |
428 | regn = loc->lr_number; | 308 | regn = op->number; |
429 | } else | 309 | } else |
430 | die("Dwarf_OP %d is not supported.", op); | 310 | die("DW_OP %d is not supported.", op->atom); |
431 | 311 | ||
432 | regs = get_arch_regstr(regn); | 312 | regs = get_arch_regstr(regn); |
433 | if (!regs) | 313 | if (!regs) |
434 | die("%lld exceeds max register number.", regn); | 314 | die("%u exceeds max register number.", regn); |
435 | 315 | ||
436 | if (deref) | 316 | if (deref) |
437 | ret = snprintf(pf->buf, pf->len, | 317 | ret = snprintf(pf->buf, pf->len, " %s=+%ju(%s)", |
438 | " %s=%+lld(%s)", pf->var, offs, regs); | 318 | pf->var, (uintmax_t)offs, regs); |
439 | else | 319 | else |
440 | ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); | 320 | ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); |
441 | DIE_IF(ret < 0); | 321 | DIE_IF(ret < 0); |
@@ -443,41 +323,41 @@ static void show_location(Dwarf_Loc *loc, struct probe_finder *pf) | |||
443 | } | 323 | } |
444 | 324 | ||
445 | /* Show a variables in kprobe event format */ | 325 | /* Show a variables in kprobe event format */ |
446 | static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf) | 326 | static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf) |
447 | { | 327 | { |
448 | Dwarf_Attribute attr; | 328 | Dwarf_Attribute attr; |
449 | Dwarf_Locdesc ld; | 329 | Dwarf_Op *expr; |
330 | size_t nexpr; | ||
450 | int ret; | 331 | int ret; |
451 | 332 | ||
452 | ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error); | 333 | if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) |
453 | if (ret != DW_DLV_OK) | ||
454 | goto error; | 334 | goto error; |
455 | ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base)); | 335 | /* TODO: handle more than 1 exprs */ |
456 | if (ret != DW_DLV_OK) | 336 | ret = dwarf_getlocation_addr(&attr, (pf->addr - pf->cu_base), |
337 | &expr, &nexpr, 1); | ||
338 | if (ret <= 0 || nexpr == 0) | ||
457 | goto error; | 339 | goto error; |
458 | /* TODO? */ | 340 | |
459 | DIE_IF(ld.ld_cents != 1); | 341 | show_location(expr, pf); |
460 | show_location(&ld.ld_s[0], pf); | 342 | /* *expr will be cached in libdw. Don't free it. */ |
461 | free(ld.ld_s); | ||
462 | dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); | ||
463 | return ; | 343 | return ; |
464 | error: | 344 | error: |
345 | /* TODO: Support const_value */ | ||
465 | die("Failed to find the location of %s at this address.\n" | 346 | die("Failed to find the location of %s at this address.\n" |
466 | " Perhaps, it has been optimized out.", pf->var); | 347 | " Perhaps, it has been optimized out.", pf->var); |
467 | } | 348 | } |
468 | 349 | ||
469 | static int variable_callback(struct die_link *dlink, void *data) | 350 | static int variable_search_cb(struct die_link *dlink, void *data) |
470 | { | 351 | { |
471 | struct probe_finder *pf = (struct probe_finder *)data; | 352 | struct probe_finder *pf = (struct probe_finder *)data; |
472 | Dwarf_Half tag; | 353 | int tag; |
473 | int ret; | ||
474 | 354 | ||
475 | ret = dwarf_tag(dlink->die, &tag, &__dw_error); | 355 | tag = dwarf_tag(&dlink->die); |
476 | DIE_IF(ret == DW_DLV_ERROR); | 356 | DIE_IF(tag < 0); |
477 | if ((tag == DW_TAG_formal_parameter || | 357 | if ((tag == DW_TAG_formal_parameter || |
478 | tag == DW_TAG_variable) && | 358 | tag == DW_TAG_variable) && |
479 | (die_compare_name(dlink->die, pf->var) == 0)) { | 359 | (die_compare_name(&dlink->die, pf->var) == 0)) { |
480 | show_variable(dlink->die, pf); | 360 | show_variable(&dlink->die, pf); |
481 | return 1; | 361 | return 1; |
482 | } | 362 | } |
483 | /* TODO: Support struct members and arrays */ | 363 | /* TODO: Support struct members and arrays */ |
@@ -485,7 +365,7 @@ static int variable_callback(struct die_link *dlink, void *data) | |||
485 | } | 365 | } |
486 | 366 | ||
487 | /* Find a variable in a subprogram die */ | 367 | /* Find a variable in a subprogram die */ |
488 | static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf) | 368 | static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) |
489 | { | 369 | { |
490 | int ret; | 370 | int ret; |
491 | 371 | ||
@@ -499,43 +379,25 @@ static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf) | |||
499 | 379 | ||
500 | pr_debug("Searching '%s' variable in context.\n", pf->var); | 380 | pr_debug("Searching '%s' variable in context.\n", pf->var); |
501 | /* Search child die for local variables and parameters. */ | 381 | /* Search child die for local variables and parameters. */ |
502 | ret = search_die_from_children(sp_die, variable_callback, pf); | 382 | ret = search_die_from_children(sp_die, variable_search_cb, pf); |
503 | if (!ret) | 383 | if (!ret) |
504 | die("Failed to find '%s' in this function.", pf->var); | 384 | die("Failed to find '%s' in this function.", pf->var); |
505 | } | 385 | } |
506 | 386 | ||
507 | /* Get a frame base on the address */ | ||
508 | static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf) | ||
509 | { | ||
510 | Dwarf_Attribute attr; | ||
511 | int ret; | ||
512 | |||
513 | ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error); | ||
514 | DIE_IF(ret != DW_DLV_OK); | ||
515 | ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base)); | ||
516 | DIE_IF(ret != DW_DLV_OK); | ||
517 | dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); | ||
518 | } | ||
519 | |||
520 | static void free_current_frame_base(struct probe_finder *pf) | ||
521 | { | ||
522 | free(pf->fbloc.ld_s); | ||
523 | memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc)); | ||
524 | } | ||
525 | |||
526 | /* Show a probe point to output buffer */ | 387 | /* Show a probe point to output buffer */ |
527 | static void show_probe_point(Dwarf_Die sp_die, Dwarf_Signed offs, | 388 | static void show_probe_point(Dwarf_Die *sp_die, size_t offs, |
528 | struct probe_finder *pf) | 389 | struct probe_finder *pf) |
529 | { | 390 | { |
530 | struct probe_point *pp = pf->pp; | 391 | struct probe_point *pp = pf->pp; |
531 | char *name; | 392 | const char *name; |
532 | char tmp[MAX_PROBE_BUFFER]; | 393 | char tmp[MAX_PROBE_BUFFER]; |
533 | int ret, i, len; | 394 | int ret, i, len; |
395 | Dwarf_Attribute fb_attr; | ||
396 | size_t nops; | ||
534 | 397 | ||
535 | /* Output name of probe point */ | 398 | /* Output name of probe point */ |
536 | ret = dwarf_diename(sp_die, &name, &__dw_error); | 399 | name = dwarf_diename(sp_die); |
537 | DIE_IF(ret == DW_DLV_ERROR); | 400 | if (name) { |
538 | if (ret == DW_DLV_OK) { | ||
539 | ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name, | 401 | ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name, |
540 | (unsigned int)offs); | 402 | (unsigned int)offs); |
541 | /* Copy the function name if possible */ | 403 | /* Copy the function name if possible */ |
@@ -543,14 +405,14 @@ static void show_probe_point(Dwarf_Die sp_die, Dwarf_Signed offs, | |||
543 | pp->function = strdup(name); | 405 | pp->function = strdup(name); |
544 | pp->offset = offs; | 406 | pp->offset = offs; |
545 | } | 407 | } |
546 | dwarf_dealloc(__dw_debug, name, DW_DLA_STRING); | ||
547 | } else { | 408 | } else { |
548 | /* This function has no name. */ | 409 | /* This function has no name. */ |
549 | ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr); | 410 | ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx", |
411 | (uintmax_t)pf->addr); | ||
550 | if (!pp->function) { | 412 | if (!pp->function) { |
551 | /* TODO: Use _stext */ | 413 | /* TODO: Use _stext */ |
552 | pp->function = strdup(""); | 414 | pp->function = strdup(""); |
553 | pp->offset = (int)pf->addr; | 415 | pp->offset = (size_t)pf->addr; |
554 | } | 416 | } |
555 | } | 417 | } |
556 | DIE_IF(ret < 0); | 418 | DIE_IF(ret < 0); |
@@ -558,8 +420,15 @@ static void show_probe_point(Dwarf_Die sp_die, Dwarf_Signed offs, | |||
558 | len = ret; | 420 | len = ret; |
559 | pr_debug("Probe point found: %s\n", tmp); | 421 | pr_debug("Probe point found: %s\n", tmp); |
560 | 422 | ||
423 | /* Get the frame base attribute/ops */ | ||
424 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); | ||
425 | ret = dwarf_getlocation_addr(&fb_attr, (pf->addr - pf->cu_base), | ||
426 | &pf->fb_ops, &nops, 1); | ||
427 | if (ret <= 0 || nops == 0) | ||
428 | pf->fb_ops = NULL; | ||
429 | |||
561 | /* Find each argument */ | 430 | /* Find each argument */ |
562 | get_current_frame_base(sp_die, pf); | 431 | /* TODO: use dwarf_cfi_addrframe */ |
563 | for (i = 0; i < pp->nr_args; i++) { | 432 | for (i = 0; i < pp->nr_args; i++) { |
564 | pf->var = pp->args[i]; | 433 | pf->var = pp->args[i]; |
565 | pf->buf = &tmp[len]; | 434 | pf->buf = &tmp[len]; |
@@ -567,131 +436,106 @@ static void show_probe_point(Dwarf_Die sp_die, Dwarf_Signed offs, | |||
567 | find_variable(sp_die, pf); | 436 | find_variable(sp_die, pf); |
568 | len += strlen(pf->buf); | 437 | len += strlen(pf->buf); |
569 | } | 438 | } |
570 | free_current_frame_base(pf); | 439 | |
440 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ | ||
441 | pf->fb_ops = NULL; | ||
571 | 442 | ||
572 | pp->probes[pp->found] = strdup(tmp); | 443 | pp->probes[pp->found] = strdup(tmp); |
573 | pp->found++; | 444 | pp->found++; |
574 | } | 445 | } |
575 | 446 | ||
576 | static int probeaddr_callback(struct die_link *dlink, void *data) | ||
577 | { | ||
578 | struct probe_finder *pf = (struct probe_finder *)data; | ||
579 | Dwarf_Half tag; | ||
580 | Dwarf_Signed offs; | ||
581 | int ret; | ||
582 | |||
583 | ret = dwarf_tag(dlink->die, &tag, &__dw_error); | ||
584 | DIE_IF(ret == DW_DLV_ERROR); | ||
585 | /* Check the address is in this subprogram */ | ||
586 | if (tag == DW_TAG_subprogram && | ||
587 | die_within_subprogram(dlink->die, pf->addr, &offs)) { | ||
588 | show_probe_point(dlink->die, offs, pf); | ||
589 | return 1; | ||
590 | } | ||
591 | return 0; | ||
592 | } | ||
593 | |||
594 | /* Find probe point from its line number */ | 447 | /* Find probe point from its line number */ |
595 | static void find_probe_point_by_line(struct probe_finder *pf) | 448 | static void find_probe_point_by_line(struct probe_finder *pf) |
596 | { | 449 | { |
597 | Dwarf_Signed cnt, i, clm; | 450 | Dwarf_Lines *lines; |
598 | Dwarf_Line *lines; | 451 | Dwarf_Line *line; |
599 | Dwarf_Unsigned lineno = 0; | 452 | size_t nlines, i; |
600 | Dwarf_Addr addr; | 453 | Dwarf_Addr addr, epc; |
601 | Dwarf_Unsigned fno; | 454 | int lineno; |
602 | int ret; | 455 | int ret; |
456 | Dwarf_Die *sp_die, die_mem; | ||
603 | 457 | ||
604 | ret = dwarf_srclines(pf->cu_die, &lines, &cnt, &__dw_error); | 458 | ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines); |
605 | DIE_IF(ret != DW_DLV_OK); | 459 | DIE_IF(ret != 0); |
606 | |||
607 | for (i = 0; i < cnt; i++) { | ||
608 | ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error); | ||
609 | DIE_IF(ret != DW_DLV_OK); | ||
610 | if (fno != pf->fno) | ||
611 | continue; | ||
612 | 460 | ||
613 | ret = dwarf_lineno(lines[i], &lineno, &__dw_error); | 461 | for (i = 0; i < nlines; i++) { |
614 | DIE_IF(ret != DW_DLV_OK); | 462 | line = dwarf_onesrcline(lines, i); |
463 | dwarf_lineno(line, &lineno); | ||
615 | if (lineno != pf->lno) | 464 | if (lineno != pf->lno) |
616 | continue; | 465 | continue; |
617 | 466 | ||
618 | ret = dwarf_lineoff(lines[i], &clm, &__dw_error); | 467 | /* TODO: Get fileno from line, but how? */ |
619 | DIE_IF(ret != DW_DLV_OK); | 468 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) |
469 | continue; | ||
620 | 470 | ||
621 | ret = dwarf_lineaddr(lines[i], &addr, &__dw_error); | 471 | ret = dwarf_lineaddr(line, &addr); |
622 | DIE_IF(ret != DW_DLV_OK); | 472 | DIE_IF(ret != 0); |
623 | pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n", | 473 | pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n", |
624 | (int)i, (unsigned)lineno, (int)clm, addr); | 474 | (int)i, lineno, (uintmax_t)addr); |
625 | pf->addr = addr; | 475 | pf->addr = addr; |
626 | /* Search a real subprogram including this line, */ | 476 | |
627 | ret = search_die_from_children(pf->cu_die, | 477 | sp_die = die_get_real_subprogram(&pf->cu_die, addr, &die_mem); |
628 | probeaddr_callback, pf); | 478 | if (!sp_die) |
629 | if (ret == 0) | ||
630 | die("Probe point is not found in subprograms."); | 479 | die("Probe point is not found in subprograms."); |
480 | dwarf_entrypc(sp_die, &epc); | ||
481 | show_probe_point(sp_die, (size_t)(addr - epc), pf); | ||
631 | /* Continuing, because target line might be inlined. */ | 482 | /* Continuing, because target line might be inlined. */ |
632 | } | 483 | } |
633 | dwarf_srclines_dealloc(__dw_debug, lines, cnt); | ||
634 | } | 484 | } |
635 | 485 | ||
486 | |||
636 | /* Search function from function name */ | 487 | /* Search function from function name */ |
637 | static int probefunc_callback(struct die_link *dlink, void *data) | 488 | static int probe_point_search_cb(struct die_link *dlink, void *data) |
638 | { | 489 | { |
639 | struct probe_finder *pf = (struct probe_finder *)data; | 490 | struct probe_finder *pf = (struct probe_finder *)data; |
640 | struct probe_point *pp = pf->pp; | 491 | struct probe_point *pp = pf->pp; |
641 | struct die_link *lk; | 492 | struct die_link *lk; |
642 | Dwarf_Signed offs; | 493 | size_t offs; |
643 | Dwarf_Half tag; | 494 | int tag; |
644 | int ret; | 495 | int ret; |
645 | 496 | ||
646 | ret = dwarf_tag(dlink->die, &tag, &__dw_error); | 497 | tag = dwarf_tag(&dlink->die); |
647 | DIE_IF(ret == DW_DLV_ERROR); | ||
648 | if (tag == DW_TAG_subprogram) { | 498 | if (tag == DW_TAG_subprogram) { |
649 | if (die_compare_name(dlink->die, pp->function) == 0) { | 499 | if (die_compare_name(&dlink->die, pp->function) == 0) { |
650 | if (pp->line) { /* Function relative line */ | 500 | if (pp->line) { /* Function relative line */ |
651 | pf->fno = die_get_decl_file(dlink->die); | 501 | pf->fname = dwarf_decl_file(&dlink->die); |
652 | pf->lno = die_get_decl_line(dlink->die) | 502 | dwarf_decl_line(&dlink->die, &pf->lno); |
653 | + pp->line; | 503 | pf->lno += pp->line; |
654 | find_probe_point_by_line(pf); | 504 | find_probe_point_by_line(pf); |
655 | return 1; | 505 | return 1; |
656 | } | 506 | } |
657 | if (die_inlined_subprogram(dlink->die)) { | 507 | if (dwarf_func_inline(&dlink->die)) { |
658 | /* Inlined function, save it. */ | 508 | /* Inlined function, save it. */ |
659 | ret = dwarf_die_CU_offset(dlink->die, | 509 | pf->origin = dlink->die.addr; |
660 | &pf->inl_offs, | ||
661 | &__dw_error); | ||
662 | DIE_IF(ret != DW_DLV_OK); | ||
663 | pr_debug("inline definition offset %lld\n", | ||
664 | pf->inl_offs); | ||
665 | return 0; /* Continue to search */ | 510 | return 0; /* Continue to search */ |
666 | } | 511 | } |
667 | /* Get probe address */ | 512 | /* Get probe address */ |
668 | pf->addr = die_get_entrypc(dlink->die); | 513 | pf->addr = die_get_entrypc(&dlink->die); |
669 | pf->addr += pp->offset; | 514 | pf->addr += pp->offset; |
670 | /* TODO: Check the address in this function */ | 515 | /* TODO: Check the address in this function */ |
671 | show_probe_point(dlink->die, pp->offset, pf); | 516 | show_probe_point(&dlink->die, pp->offset, pf); |
672 | return 1; /* Exit; no same symbol in this CU. */ | 517 | return 1; /* Exit; no same symbol in this CU. */ |
673 | } | 518 | } |
674 | } else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) { | 519 | } else if (tag == DW_TAG_inlined_subroutine && pf->origin) { |
675 | if (die_get_abstract_origin(dlink->die) == pf->inl_offs) { | 520 | if (die_compare_abstract_origin(&dlink->die, pf->origin)) { |
676 | /* Get probe address */ | 521 | /* Get probe address */ |
677 | pf->addr = die_get_entrypc(dlink->die); | 522 | pf->addr = die_get_entrypc(&dlink->die); |
678 | pf->addr += pp->offset; | 523 | pf->addr += pp->offset; |
679 | pr_debug("found inline addr: 0x%llx\n", pf->addr); | 524 | pr_debug("found inline addr: 0x%jx\n", |
525 | (uintmax_t)pf->addr); | ||
680 | /* Inlined function. Get a real subprogram */ | 526 | /* Inlined function. Get a real subprogram */ |
681 | for (lk = dlink->parent; lk != NULL; lk = lk->parent) { | 527 | for (lk = dlink->parent; lk != NULL; lk = lk->parent) { |
682 | tag = 0; | 528 | tag = dwarf_tag(&lk->die); |
683 | dwarf_tag(lk->die, &tag, &__dw_error); | ||
684 | DIE_IF(ret == DW_DLV_ERROR); | ||
685 | if (tag == DW_TAG_subprogram && | 529 | if (tag == DW_TAG_subprogram && |
686 | !die_inlined_subprogram(lk->die)) | 530 | !dwarf_func_inline(&lk->die)) |
687 | goto found; | 531 | goto found; |
688 | } | 532 | } |
689 | die("Failed to find real subprogram."); | 533 | die("Failed to find real subprogram."); |
690 | found: | 534 | found: |
691 | /* Get offset from subprogram */ | 535 | /* Get offset from subprogram */ |
692 | ret = die_within_subprogram(lk->die, pf->addr, &offs); | 536 | ret = die_within_subprogram(&lk->die, pf->addr, &offs); |
693 | DIE_IF(!ret); | 537 | DIE_IF(!ret); |
694 | show_probe_point(lk->die, offs, pf); | 538 | show_probe_point(&lk->die, offs, pf); |
695 | /* Continue to search */ | 539 | /* Continue to search */ |
696 | } | 540 | } |
697 | } | 541 | } |
@@ -700,43 +544,43 @@ found: | |||
700 | 544 | ||
701 | static void find_probe_point_by_func(struct probe_finder *pf) | 545 | static void find_probe_point_by_func(struct probe_finder *pf) |
702 | { | 546 | { |
703 | search_die_from_children(pf->cu_die, probefunc_callback, pf); | 547 | search_die_from_children(&pf->cu_die, probe_point_search_cb, pf); |
704 | } | 548 | } |
705 | 549 | ||
706 | /* Find a probe point */ | 550 | /* Find a probe point */ |
707 | int find_probe_point(int fd, struct probe_point *pp) | 551 | int find_probe_point(int fd, struct probe_point *pp) |
708 | { | 552 | { |
709 | Dwarf_Half addr_size = 0; | ||
710 | Dwarf_Unsigned next_cuh = 0; | ||
711 | int cu_number = 0, ret; | ||
712 | struct probe_finder pf = {.pp = pp}; | 553 | struct probe_finder pf = {.pp = pp}; |
713 | 554 | int ret; | |
714 | ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); | 555 | Dwarf_Off off, noff; |
715 | if (ret != DW_DLV_OK) | 556 | size_t cuhl; |
557 | Dwarf_Die *diep; | ||
558 | Dwarf *dbg; | ||
559 | int fno = 0; | ||
560 | |||
561 | dbg = dwarf_begin(fd, DWARF_C_READ); | ||
562 | if (!dbg) | ||
716 | return -ENOENT; | 563 | return -ENOENT; |
717 | 564 | ||
718 | pp->found = 0; | 565 | pp->found = 0; |
719 | while (++cu_number) { | 566 | off = 0; |
720 | /* Search CU (Compilation Unit) */ | 567 | /* Loop on CUs (Compilation Unit) */ |
721 | ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL, | 568 | while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { |
722 | &addr_size, &next_cuh, &__dw_error); | ||
723 | DIE_IF(ret == DW_DLV_ERROR); | ||
724 | if (ret == DW_DLV_NO_ENTRY) | ||
725 | break; | ||
726 | |||
727 | /* Get the DIE(Debugging Information Entry) of this CU */ | 569 | /* Get the DIE(Debugging Information Entry) of this CU */ |
728 | ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error); | 570 | diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die); |
729 | DIE_IF(ret != DW_DLV_OK); | 571 | if (!diep) |
572 | continue; | ||
730 | 573 | ||
731 | /* Check if target file is included. */ | 574 | /* Check if target file is included. */ |
732 | if (pp->file) | 575 | if (pp->file) |
733 | pf.fno = cu_find_fileno(pf.cu_die, pp->file); | 576 | fno = cu_find_fileno(&pf.cu_die, pp->file); |
577 | else | ||
578 | fno = 0; | ||
734 | 579 | ||
735 | if (!pp->file || pf.fno) { | 580 | if (!pp->file || fno) { |
736 | /* Save CU base address (for frame_base) */ | 581 | /* Save CU base address (for frame_base) */ |
737 | ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error); | 582 | ret = dwarf_lowpc(&pf.cu_die, &pf.cu_base); |
738 | DIE_IF(ret == DW_DLV_ERROR); | 583 | if (ret != 0) |
739 | if (ret == DW_DLV_NO_ENTRY) | ||
740 | pf.cu_base = 0; | 584 | pf.cu_base = 0; |
741 | if (pp->function) | 585 | if (pp->function) |
742 | find_probe_point_by_func(&pf); | 586 | find_probe_point_by_func(&pf); |
@@ -745,10 +589,9 @@ int find_probe_point(int fd, struct probe_point *pp) | |||
745 | find_probe_point_by_line(&pf); | 589 | find_probe_point_by_line(&pf); |
746 | } | 590 | } |
747 | } | 591 | } |
748 | dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE); | 592 | off = noff; |
749 | } | 593 | } |
750 | ret = dwarf_finish(__dw_debug, &__dw_error); | 594 | dwarf_end(dbg); |
751 | DIE_IF(ret != DW_DLV_OK); | ||
752 | 595 | ||
753 | return pp->found; | 596 | return pp->found; |
754 | } | 597 | } |
@@ -781,69 +624,76 @@ found: | |||
781 | /* Find line range from its line number */ | 624 | /* Find line range from its line number */ |
782 | static void find_line_range_by_line(struct line_finder *lf) | 625 | static void find_line_range_by_line(struct line_finder *lf) |
783 | { | 626 | { |
784 | Dwarf_Signed cnt, i; | 627 | Dwarf_Lines *lines; |
785 | Dwarf_Line *lines; | 628 | Dwarf_Line *line; |
786 | Dwarf_Unsigned lineno = 0; | 629 | size_t nlines, i; |
787 | Dwarf_Unsigned fno; | ||
788 | Dwarf_Addr addr; | 630 | Dwarf_Addr addr; |
631 | int lineno; | ||
789 | int ret; | 632 | int ret; |
633 | const char *src; | ||
790 | 634 | ||
791 | INIT_LIST_HEAD(&lf->lr->line_list); | 635 | INIT_LIST_HEAD(&lf->lr->line_list); |
792 | ret = dwarf_srclines(lf->cu_die, &lines, &cnt, &__dw_error); | 636 | ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines); |
793 | DIE_IF(ret != DW_DLV_OK); | 637 | DIE_IF(ret != 0); |
794 | 638 | ||
795 | for (i = 0; i < cnt; i++) { | 639 | for (i = 0; i < nlines; i++) { |
796 | ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error); | 640 | line = dwarf_onesrcline(lines, i); |
797 | DIE_IF(ret != DW_DLV_OK); | 641 | dwarf_lineno(line, &lineno); |
798 | if (fno != lf->fno) | 642 | if (lf->lno_s > lineno || lf->lno_e < lineno) |
799 | continue; | 643 | continue; |
800 | 644 | ||
801 | ret = dwarf_lineno(lines[i], &lineno, &__dw_error); | 645 | /* TODO: Get fileno from line, but how? */ |
802 | DIE_IF(ret != DW_DLV_OK); | 646 | src = dwarf_linesrc(line, NULL, NULL); |
803 | if (lf->lno_s > lineno || lf->lno_e < lineno) | 647 | if (strtailcmp(src, lf->fname) != 0) |
804 | continue; | 648 | continue; |
805 | 649 | ||
806 | /* Filter line in the function address range */ | 650 | /* Filter line in the function address range */ |
807 | if (lf->addr_s && lf->addr_e) { | 651 | if (lf->addr_s && lf->addr_e) { |
808 | ret = dwarf_lineaddr(lines[i], &addr, &__dw_error); | 652 | ret = dwarf_lineaddr(line, &addr); |
809 | DIE_IF(ret != DW_DLV_OK); | 653 | DIE_IF(ret != 0); |
810 | if (lf->addr_s > addr || lf->addr_e <= addr) | 654 | if (lf->addr_s > addr || lf->addr_e <= addr) |
811 | continue; | 655 | continue; |
812 | } | 656 | } |
657 | /* Copy real path */ | ||
658 | if (!lf->lr->path) | ||
659 | lf->lr->path = strdup(src); | ||
813 | line_range_add_line(lf->lr, (unsigned int)lineno); | 660 | line_range_add_line(lf->lr, (unsigned int)lineno); |
814 | } | 661 | } |
815 | dwarf_srclines_dealloc(__dw_debug, lines, cnt); | 662 | /* Update status */ |
816 | if (!list_empty(&lf->lr->line_list)) | 663 | if (!list_empty(&lf->lr->line_list)) |
817 | lf->found = 1; | 664 | lf->found = 1; |
665 | else { | ||
666 | free(lf->lr->path); | ||
667 | lf->lr->path = NULL; | ||
668 | } | ||
818 | } | 669 | } |
819 | 670 | ||
820 | /* Search function from function name */ | 671 | /* Search function from function name */ |
821 | static int linefunc_callback(struct die_link *dlink, void *data) | 672 | static int line_range_search_cb(struct die_link *dlink, void *data) |
822 | { | 673 | { |
823 | struct line_finder *lf = (struct line_finder *)data; | 674 | struct line_finder *lf = (struct line_finder *)data; |
824 | struct line_range *lr = lf->lr; | 675 | struct line_range *lr = lf->lr; |
825 | Dwarf_Half tag; | 676 | int tag; |
826 | int ret; | 677 | int ret; |
827 | 678 | ||
828 | ret = dwarf_tag(dlink->die, &tag, &__dw_error); | 679 | tag = dwarf_tag(&dlink->die); |
829 | DIE_IF(ret == DW_DLV_ERROR); | ||
830 | if (tag == DW_TAG_subprogram && | 680 | if (tag == DW_TAG_subprogram && |
831 | die_compare_name(dlink->die, lr->function) == 0) { | 681 | die_compare_name(&dlink->die, lr->function) == 0) { |
832 | /* Get the address range of this function */ | 682 | /* Get the address range of this function */ |
833 | ret = dwarf_highpc(dlink->die, &lf->addr_e, &__dw_error); | 683 | ret = dwarf_highpc(&dlink->die, &lf->addr_e); |
834 | if (ret == DW_DLV_OK) | 684 | if (ret == 0) |
835 | ret = dwarf_lowpc(dlink->die, &lf->addr_s, &__dw_error); | 685 | ret = dwarf_lowpc(&dlink->die, &lf->addr_s); |
836 | DIE_IF(ret == DW_DLV_ERROR); | 686 | if (ret != 0) { |
837 | if (ret == DW_DLV_NO_ENTRY) { | ||
838 | lf->addr_s = 0; | 687 | lf->addr_s = 0; |
839 | lf->addr_e = 0; | 688 | lf->addr_e = 0; |
840 | } | 689 | } |
841 | 690 | ||
842 | lf->fno = die_get_decl_file(dlink->die); | 691 | lf->fname = dwarf_decl_file(&dlink->die); |
843 | lr->offset = die_get_decl_line(dlink->die);; | 692 | dwarf_decl_line(&dlink->die, &lr->offset); |
693 | pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); | ||
844 | lf->lno_s = lr->offset + lr->start; | 694 | lf->lno_s = lr->offset + lr->start; |
845 | if (!lr->end) | 695 | if (!lr->end) |
846 | lf->lno_e = (Dwarf_Unsigned)-1; | 696 | lf->lno_e = INT_MAX; |
847 | else | 697 | else |
848 | lf->lno_e = lr->offset + lr->end; | 698 | lf->lno_e = lr->offset + lr->end; |
849 | lr->start = lf->lno_s; | 699 | lr->start = lf->lno_s; |
@@ -856,55 +706,57 @@ static int linefunc_callback(struct die_link *dlink, void *data) | |||
856 | 706 | ||
857 | static void find_line_range_by_func(struct line_finder *lf) | 707 | static void find_line_range_by_func(struct line_finder *lf) |
858 | { | 708 | { |
859 | search_die_from_children(lf->cu_die, linefunc_callback, lf); | 709 | search_die_from_children(&lf->cu_die, line_range_search_cb, lf); |
860 | } | 710 | } |
861 | 711 | ||
862 | int find_line_range(int fd, struct line_range *lr) | 712 | int find_line_range(int fd, struct line_range *lr) |
863 | { | 713 | { |
864 | Dwarf_Half addr_size = 0; | 714 | struct line_finder lf = {.lr = lr, .found = 0}; |
865 | Dwarf_Unsigned next_cuh = 0; | ||
866 | int ret; | 715 | int ret; |
867 | struct line_finder lf = {.lr = lr}; | 716 | Dwarf_Off off = 0, noff; |
868 | 717 | size_t cuhl; | |
869 | ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); | 718 | Dwarf_Die *diep; |
870 | if (ret != DW_DLV_OK) | 719 | Dwarf *dbg; |
720 | int fno; | ||
721 | |||
722 | dbg = dwarf_begin(fd, DWARF_C_READ); | ||
723 | if (!dbg) | ||
871 | return -ENOENT; | 724 | return -ENOENT; |
872 | 725 | ||
726 | /* Loop on CUs (Compilation Unit) */ | ||
873 | while (!lf.found) { | 727 | while (!lf.found) { |
874 | /* Search CU (Compilation Unit) */ | 728 | ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL); |
875 | ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL, | 729 | if (ret != 0) |
876 | &addr_size, &next_cuh, &__dw_error); | ||
877 | DIE_IF(ret == DW_DLV_ERROR); | ||
878 | if (ret == DW_DLV_NO_ENTRY) | ||
879 | break; | 730 | break; |
880 | 731 | ||
881 | /* Get the DIE(Debugging Information Entry) of this CU */ | 732 | /* Get the DIE(Debugging Information Entry) of this CU */ |
882 | ret = dwarf_siblingof(__dw_debug, 0, &lf.cu_die, &__dw_error); | 733 | diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die); |
883 | DIE_IF(ret != DW_DLV_OK); | 734 | if (!diep) |
735 | continue; | ||
884 | 736 | ||
885 | /* Check if target file is included. */ | 737 | /* Check if target file is included. */ |
886 | if (lr->file) | 738 | if (lr->file) |
887 | lf.fno = cu_find_fileno(lf.cu_die, lr->file); | 739 | fno = cu_find_fileno(&lf.cu_die, lr->file); |
740 | else | ||
741 | fno = 0; | ||
888 | 742 | ||
889 | if (!lr->file || lf.fno) { | 743 | if (!lr->file || fno) { |
890 | if (lr->function) | 744 | if (lr->function) |
891 | find_line_range_by_func(&lf); | 745 | find_line_range_by_func(&lf); |
892 | else { | 746 | else { |
747 | lf.fname = lr->file; | ||
893 | lf.lno_s = lr->start; | 748 | lf.lno_s = lr->start; |
894 | if (!lr->end) | 749 | if (!lr->end) |
895 | lf.lno_e = (Dwarf_Unsigned)-1; | 750 | lf.lno_e = INT_MAX; |
896 | else | 751 | else |
897 | lf.lno_e = lr->end; | 752 | lf.lno_e = lr->end; |
898 | find_line_range_by_line(&lf); | 753 | find_line_range_by_line(&lf); |
899 | } | 754 | } |
900 | /* Get the real file path */ | ||
901 | if (lf.found) | ||
902 | cu_get_filename(lf.cu_die, lf.fno, &lr->path); | ||
903 | } | 755 | } |
904 | dwarf_dealloc(__dw_debug, lf.cu_die, DW_DLA_DIE); | 756 | off = noff; |
905 | } | 757 | } |
906 | ret = dwarf_finish(__dw_debug, &__dw_error); | 758 | pr_debug("path: %lx\n", (unsigned long)lr->path); |
907 | DIE_IF(ret != DW_DLV_OK); | 759 | dwarf_end(dbg); |
908 | return lf.found; | 760 | return lf.found; |
909 | } | 761 | } |
910 | 762 | ||
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index b2a25241135a..9dd4a884d0e6 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
@@ -1,6 +1,7 @@ | |||
1 | #ifndef _PROBE_FINDER_H | 1 | #ifndef _PROBE_FINDER_H |
2 | #define _PROBE_FINDER_H | 2 | #define _PROBE_FINDER_H |
3 | 3 | ||
4 | #include <stdbool.h> | ||
4 | #include "util.h" | 5 | #include "util.h" |
5 | 6 | ||
6 | #define MAX_PATH_LEN 256 | 7 | #define MAX_PATH_LEN 256 |
@@ -46,53 +47,48 @@ struct line_range { | |||
46 | char *function; /* Function name */ | 47 | char *function; /* Function name */ |
47 | unsigned int start; /* Start line number */ | 48 | unsigned int start; /* Start line number */ |
48 | unsigned int end; /* End line number */ | 49 | unsigned int end; /* End line number */ |
49 | unsigned int offset; /* Start line offset */ | 50 | int offset; /* Start line offset */ |
50 | char *path; /* Real path name */ | 51 | char *path; /* Real path name */ |
51 | struct list_head line_list; /* Visible lines */ | 52 | struct list_head line_list; /* Visible lines */ |
52 | }; | 53 | }; |
53 | 54 | ||
54 | #ifndef NO_LIBDWARF | 55 | #ifndef NO_DWARF_SUPPORT |
55 | extern int find_probe_point(int fd, struct probe_point *pp); | 56 | extern int find_probe_point(int fd, struct probe_point *pp); |
56 | extern int find_line_range(int fd, struct line_range *lr); | 57 | extern int find_line_range(int fd, struct line_range *lr); |
57 | 58 | ||
58 | /* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */ | ||
59 | #ifndef _MIPS_SZLONG | ||
60 | # define _MIPS_SZLONG 0 | ||
61 | #endif | ||
62 | |||
63 | #include <dwarf.h> | 59 | #include <dwarf.h> |
64 | #include <libdwarf.h> | 60 | #include <libdw.h> |
65 | 61 | ||
66 | struct probe_finder { | 62 | struct probe_finder { |
67 | struct probe_point *pp; /* Target probe point */ | 63 | struct probe_point *pp; /* Target probe point */ |
68 | 64 | ||
69 | /* For function searching */ | 65 | /* For function searching */ |
70 | Dwarf_Addr addr; /* Address */ | 66 | Dwarf_Addr addr; /* Address */ |
71 | Dwarf_Unsigned fno; /* File number */ | 67 | const char *fname; /* File name */ |
72 | Dwarf_Unsigned lno; /* Line number */ | 68 | int lno; /* Line number */ |
73 | Dwarf_Off inl_offs; /* Inline offset */ | 69 | void *origin; /* Inline origin addr */ |
74 | Dwarf_Die cu_die; /* Current CU */ | 70 | Dwarf_Die cu_die; /* Current CU */ |
75 | 71 | ||
76 | /* For variable searching */ | 72 | /* For variable searching */ |
77 | Dwarf_Addr cu_base; /* Current CU base address */ | 73 | Dwarf_Op *fb_ops; /* Frame base attribute */ |
78 | Dwarf_Locdesc fbloc; /* Location of Current Frame Base */ | 74 | Dwarf_Addr cu_base; /* Current CU base address */ |
79 | const char *var; /* Current variable name */ | 75 | const char *var; /* Current variable name */ |
80 | char *buf; /* Current output buffer */ | 76 | char *buf; /* Current output buffer */ |
81 | int len; /* Length of output buffer */ | 77 | int len; /* Length of output buffer */ |
82 | }; | 78 | }; |
83 | 79 | ||
84 | struct line_finder { | 80 | struct line_finder { |
85 | struct line_range *lr; /* Target line range */ | 81 | struct line_range *lr; /* Target line range */ |
86 | 82 | ||
87 | Dwarf_Unsigned fno; /* File number */ | 83 | const char *fname; /* File name */ |
88 | Dwarf_Unsigned lno_s; /* Start line number */ | 84 | int lno_s; /* Start line number */ |
89 | Dwarf_Unsigned lno_e; /* End line number */ | 85 | int lno_e; /* End line number */ |
90 | Dwarf_Addr addr_s; /* Start address */ | 86 | Dwarf_Addr addr_s; /* Start address */ |
91 | Dwarf_Addr addr_e; /* End address */ | 87 | Dwarf_Addr addr_e; /* End address */ |
92 | Dwarf_Die cu_die; /* Current CU */ | 88 | Dwarf_Die cu_die; /* Current CU */ |
93 | int found; | 89 | int found; |
94 | }; | 90 | }; |
95 | 91 | ||
96 | #endif /* NO_LIBDWARF */ | 92 | #endif /* NO_DWARF_SUPPORT */ |
97 | 93 | ||
98 | #endif /*_PROBE_FINDER_H */ | 94 | #endif /*_PROBE_FINDER_H */ |