Blame view
tools/perf/util/probe-finder.c
46.5 KB
4ea42b181 perf: Add perf pr... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/* * probe-finder.c : C expression to kprobe event converter * * Written by Masami Hiramatsu <mhiramat@redhat.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ |
fd20e8111 perf tools: Inclu... |
21 |
#include <inttypes.h> |
4ea42b181 perf: Add perf pr... |
22 23 24 25 26 27 28 |
#include <sys/utsname.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <stdio.h> #include <unistd.h> |
4ea42b181 perf: Add perf pr... |
29 30 31 |
#include <stdlib.h> #include <string.h> #include <stdarg.h> |
cd932c593 perf: Move arch s... |
32 |
#include <dwarf-regs.h> |
074fc0e4b perf: Use die() f... |
33 |
|
124bb83cd perf probe: Add b... |
34 |
#include <linux/bitops.h> |
89c69c0ee perf: Use eprintf... |
35 |
#include "event.h" |
a15ad2f53 perf probe: Suppo... |
36 |
#include "dso.h" |
89c69c0ee perf: Use eprintf... |
37 |
#include "debug.h" |
5a62257a3 perf probe: Repla... |
38 |
#include "intlist.h" |
074fc0e4b perf: Use die() f... |
39 |
#include "util.h" |
8ec20b176 perf str{filter,l... |
40 |
#include "strlist.h" |
9ed7e1b85 perf probe: Add k... |
41 |
#include "symbol.h" |
4ea42b181 perf: Add perf pr... |
42 |
#include "probe-finder.h" |
180b20616 perf probe: Add s... |
43 |
#include "probe-file.h" |
a067558e2 perf tools: Move ... |
44 |
#include "string2.h" |
4ea42b181 perf: Add perf pr... |
45 |
|
4984912eb perf probe: Query... |
46 47 |
/* Kprobe tracer basic type is up to u64 */ #define MAX_BASIC_TYPE_BITS 64 |
469b9b884 perf probe: Add b... |
48 |
/* Dwarf FL wrappers */ |
469b9b884 perf probe: Add b... |
49 50 51 52 53 54 55 56 57 58 59 |
static char *debuginfo_path; /* Currently dummy */ static const Dwfl_Callbacks offline_callbacks = { .find_debuginfo = dwfl_standard_find_debuginfo, .debuginfo_path = &debuginfo_path, .section_address = dwfl_offline_section_address, /* We use this table for core files too. */ .find_elf = dwfl_build_id_find_elf, }; |
469b9b884 perf probe: Add b... |
60 |
/* Get a Dwarf from offline image */ |
316c7136f perf tools: Finis... |
61 |
static int debuginfo__init_offline_dwarf(struct debuginfo *dbg, |
ff7417835 perf probe: Intro... |
62 |
const char *path) |
469b9b884 perf probe: Add b... |
63 |
{ |
ff7417835 perf probe: Intro... |
64 |
int fd; |
469b9b884 perf probe: Add b... |
65 |
|
ff7417835 perf probe: Intro... |
66 67 68 |
fd = open(path, O_RDONLY); if (fd < 0) return fd; |
469b9b884 perf probe: Add b... |
69 |
|
316c7136f perf tools: Finis... |
70 71 |
dbg->dwfl = dwfl_begin(&offline_callbacks); if (!dbg->dwfl) |
ff7417835 perf probe: Intro... |
72 |
goto error; |
469b9b884 perf probe: Add b... |
73 |
|
9135949dd perf probe: Begin... |
74 |
dwfl_report_begin(dbg->dwfl); |
316c7136f perf tools: Finis... |
75 76 |
dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd); if (!dbg->mod) |
469b9b884 perf probe: Add b... |
77 |
goto error; |
316c7136f perf tools: Finis... |
78 79 |
dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias); if (!dbg->dbg) |
ff7417835 perf probe: Intro... |
80 |
goto error; |
9135949dd perf probe: Begin... |
81 |
dwfl_report_end(dbg->dwfl, NULL, NULL); |
ff7417835 perf probe: Intro... |
82 |
return 0; |
469b9b884 perf probe: Add b... |
83 |
error: |
316c7136f perf tools: Finis... |
84 85 |
if (dbg->dwfl) dwfl_end(dbg->dwfl); |
ff7417835 perf probe: Intro... |
86 87 |
else close(fd); |
316c7136f perf tools: Finis... |
88 |
memset(dbg, 0, sizeof(*dbg)); |
ff7417835 perf probe: Intro... |
89 90 |
return -ENOENT; |
469b9b884 perf probe: Add b... |
91 |
} |
a15ad2f53 perf probe: Suppo... |
92 |
static struct debuginfo *__debuginfo__new(const char *path) |
ff7417835 perf probe: Intro... |
93 |
{ |
316c7136f perf tools: Finis... |
94 95 |
struct debuginfo *dbg = zalloc(sizeof(*dbg)); if (!dbg) |
3b4694de3 perf probe: Fix t... |
96 |
return NULL; |
046625231 perf tools: Intro... |
97 98 |
if (debuginfo__init_offline_dwarf(dbg, path) < 0) zfree(&dbg); |
a15ad2f53 perf probe: Suppo... |
99 100 101 |
if (dbg) pr_debug("Open Debuginfo file: %s ", path); |
316c7136f perf tools: Finis... |
102 |
return dbg; |
ff7417835 perf probe: Intro... |
103 |
} |
a15ad2f53 perf probe: Suppo... |
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 131 |
enum dso_binary_type distro_dwarf_types[] = { DSO_BINARY_TYPE__FEDORA_DEBUGINFO, DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, DSO_BINARY_TYPE__BUILDID_DEBUGINFO, DSO_BINARY_TYPE__NOT_FOUND, }; struct debuginfo *debuginfo__new(const char *path) { enum dso_binary_type *type; char buf[PATH_MAX], nil = '\0'; struct dso *dso; struct debuginfo *dinfo = NULL; /* Try to open distro debuginfo files */ dso = dso__new(path); if (!dso) goto out; for (type = distro_dwarf_types; !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND; type++) { if (dso__read_binary_type_filename(dso, *type, &nil, buf, PATH_MAX) < 0) continue; dinfo = __debuginfo__new(buf); } |
d3a7c489c perf tools: Refer... |
132 |
dso__put(dso); |
a15ad2f53 perf probe: Suppo... |
133 134 135 136 137 |
out: /* if failed to open all distro debuginfo, open given binary */ return dinfo ? : __debuginfo__new(path); } |
316c7136f perf tools: Finis... |
138 |
void debuginfo__delete(struct debuginfo *dbg) |
ff7417835 perf probe: Intro... |
139 |
{ |
316c7136f perf tools: Finis... |
140 141 142 143 |
if (dbg) { if (dbg->dwfl) dwfl_end(dbg->dwfl); free(dbg); |
ff7417835 perf probe: Intro... |
144 |
} |
3b4694de3 perf probe: Fix t... |
145 |
} |
469b9b884 perf probe: Add b... |
146 |
|
4ea42b181 perf: Add perf pr... |
147 148 149 |
/* * Probe finder related functions */ |
0e60836bb perf probe: Renam... |
150 |
static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) |
b7dcb857c perf probe: Suppo... |
151 |
{ |
0e60836bb perf probe: Renam... |
152 153 |
struct probe_trace_arg_ref *ref; ref = zalloc(sizeof(struct probe_trace_arg_ref)); |
b7dcb857c perf probe: Suppo... |
154 155 156 157 |
if (ref != NULL) ref->offset = offs; return ref; } |
cf6eb489e perf probe: Show ... |
158 159 160 |
/* * Convert a location into trace_arg. * If tvar == NULL, this just checks variable can be converted. |
3d918a12a perf probe: Find ... |
161 162 |
* If fentry == true and vr_die is a parameter, do huristic search * for the location fuzzed by function entry mcount. |
cf6eb489e perf probe: Show ... |
163 164 |
*/ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, |
3d918a12a perf probe: Find ... |
165 |
Dwarf_Op *fb_ops, Dwarf_Die *sp_die, |
293d5b439 perf probe: Suppo... |
166 |
unsigned int machine, |
cf6eb489e perf probe: Show ... |
167 |
struct probe_trace_arg *tvar) |
4ea42b181 perf: Add perf pr... |
168 |
{ |
b7dcb857c perf probe: Suppo... |
169 |
Dwarf_Attribute attr; |
3d918a12a perf probe: Find ... |
170 |
Dwarf_Addr tmp = 0; |
b7dcb857c perf probe: Suppo... |
171 172 |
Dwarf_Op *op; size_t nops; |
804b36068 perf probe: Use e... |
173 174 |
unsigned int regn; Dwarf_Word offs = 0; |
4235b0454 perf probe: Intro... |
175 |
bool ref = false; |
4ea42b181 perf: Add perf pr... |
176 |
const char *regs; |
349e8d261 perf probe: Add -... |
177 |
int ret, ret2 = 0; |
b7dcb857c perf probe: Suppo... |
178 |
|
632941c4f perf probe: Suppo... |
179 180 |
if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) goto static_var; |
b7dcb857c perf probe: Suppo... |
181 |
/* TODO: handle more than 1 exprs */ |
3d918a12a perf probe: Find ... |
182 183 184 185 |
if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) return -EINVAL; /* Broken DIE ? */ if (dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0) { ret = dwarf_entrypc(sp_die, &tmp); |
349e8d261 perf probe: Add -... |
186 187 188 189 190 191 192 193 194 195 196 197 198 |
if (ret) return -ENOENT; if (probe_conf.show_location_range && (dwarf_tag(vr_die) == DW_TAG_variable)) { ret2 = -ERANGE; } else if (addr != tmp || dwarf_tag(vr_die) != DW_TAG_formal_parameter) { return -ENOENT; } ret = dwarf_highpc(sp_die, &tmp); if (ret) |
3d918a12a perf probe: Find ... |
199 200 201 202 203 204 205 206 207 208 |
return -ENOENT; /* * This is fuzzed by fentry mcount. We try to find the * parameter location at the earliest address. */ for (addr += 1; addr <= tmp; addr++) { if (dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) > 0) goto found; } |
b7dcb857c perf probe: Suppo... |
209 210 |
return -ENOENT; } |
3d918a12a perf probe: Find ... |
211 212 213 214 |
found: if (nops == 0) /* TODO: Support const_value */ return -ENOENT; |
b7dcb857c perf probe: Suppo... |
215 216 |
if (op->atom == DW_OP_addr) { |
632941c4f perf probe: Suppo... |
217 |
static_var: |
cf6eb489e perf probe: Show ... |
218 |
if (!tvar) |
349e8d261 perf probe: Add -... |
219 |
return ret2; |
b7dcb857c perf probe: Suppo... |
220 221 222 223 224 225 226 227 228 |
/* Static variables on memory (not stack), make @varname */ ret = strlen(dwarf_diename(vr_die)); tvar->value = zalloc(ret + 2); if (tvar->value == NULL) return -ENOMEM; snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); tvar->ref = alloc_trace_arg_ref((long)offs); if (tvar->ref == NULL) return -ENOMEM; |
349e8d261 perf probe: Add -... |
229 |
return ret2; |
b7dcb857c perf probe: Suppo... |
230 |
} |
4ea42b181 perf: Add perf pr... |
231 |
|
4ea42b181 perf: Add perf pr... |
232 |
/* If this is based on frame buffer, set the offset */ |
804b36068 perf probe: Use e... |
233 |
if (op->atom == DW_OP_fbreg) { |
cf6eb489e perf probe: Show ... |
234 |
if (fb_ops == NULL) |
b55a87ade perf probe: Remov... |
235 |
return -ENOTSUP; |
4235b0454 perf probe: Intro... |
236 |
ref = true; |
804b36068 perf probe: Use e... |
237 |
offs = op->number; |
cf6eb489e perf probe: Show ... |
238 |
op = &fb_ops[0]; |
804b36068 perf probe: Use e... |
239 |
} |
4ea42b181 perf: Add perf pr... |
240 |
|
804b36068 perf probe: Use e... |
241 242 243 |
if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { regn = op->atom - DW_OP_breg0; offs += op->number; |
4235b0454 perf probe: Intro... |
244 |
ref = true; |
804b36068 perf probe: Use e... |
245 246 247 248 249 |
} else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { regn = op->atom - DW_OP_reg0; } else if (op->atom == DW_OP_bregx) { regn = op->number; offs += op->number2; |
4235b0454 perf probe: Intro... |
250 |
ref = true; |
804b36068 perf probe: Use e... |
251 252 |
} else if (op->atom == DW_OP_regx) { regn = op->number; |
b55a87ade perf probe: Remov... |
253 |
} else { |
cf6eb489e perf probe: Show ... |
254 255 |
pr_debug("DW_OP %x is not supported. ", op->atom); |
b55a87ade perf probe: Remov... |
256 257 |
return -ENOTSUP; } |
4ea42b181 perf: Add perf pr... |
258 |
|
cf6eb489e perf probe: Show ... |
259 |
if (!tvar) |
349e8d261 perf probe: Add -... |
260 |
return ret2; |
cf6eb489e perf probe: Show ... |
261 |
|
293d5b439 perf probe: Suppo... |
262 |
regs = get_dwarf_regstr(regn, machine); |
b55a87ade perf probe: Remov... |
263 |
if (!regs) { |
cf6eb489e perf probe: Show ... |
264 |
/* This should be a bug in DWARF or this tool */ |
0e43e5d22 perf probe: Clean... |
265 266 267 |
pr_warning("Mapping for the register number %u " "missing on this architecture. ", regn); |
349e8d261 perf probe: Add -... |
268 |
return -ENOTSUP; |
b55a87ade perf probe: Remov... |
269 |
} |
4ea42b181 perf: Add perf pr... |
270 |
|
02b95dadc perf probe: Remov... |
271 272 273 |
tvar->value = strdup(regs); if (tvar->value == NULL) return -ENOMEM; |
4235b0454 perf probe: Intro... |
274 |
if (ref) { |
b7dcb857c perf probe: Suppo... |
275 |
tvar->ref = alloc_trace_arg_ref((long)offs); |
e334016f1 perf probe: Remov... |
276 277 |
if (tvar->ref == NULL) return -ENOMEM; |
4235b0454 perf probe: Intro... |
278 |
} |
349e8d261 perf probe: Add -... |
279 |
return ret2; |
4ea42b181 perf: Add perf pr... |
280 |
} |
124bb83cd perf probe: Add b... |
281 |
#define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long)) |
b55a87ade perf probe: Remov... |
282 |
static int convert_variable_type(Dwarf_Die *vr_die, |
0e60836bb perf probe: Renam... |
283 |
struct probe_trace_arg *tvar, |
73317b954 perf probe: Suppo... |
284 |
const char *cast) |
4984912eb perf probe: Query... |
285 |
{ |
0e60836bb perf probe: Renam... |
286 |
struct probe_trace_arg_ref **ref_ptr = &tvar->ref; |
4984912eb perf probe: Query... |
287 288 |
Dwarf_Die type; char buf[16]; |
5f03cba41 perf probe: Make ... |
289 |
char sbuf[STRERR_BUFSIZE]; |
bcfc08215 perf probe: Remov... |
290 |
int bsize, boffs, total; |
4984912eb perf probe: Query... |
291 |
int ret; |
925437872 perf probe: Suppo... |
292 |
char prefix; |
4984912eb perf probe: Query... |
293 |
|
73317b954 perf probe: Suppo... |
294 |
/* TODO: check all types */ |
925437872 perf probe: Suppo... |
295 |
if (cast && strcmp(cast, "string") != 0 && strcmp(cast, "x") != 0 && |
19f00b011 perf probe: Suppo... |
296 |
strcmp(cast, "s") != 0 && strcmp(cast, "u") != 0) { |
73317b954 perf probe: Suppo... |
297 |
/* Non string type is OK */ |
925437872 perf probe: Suppo... |
298 |
/* and respect signedness/hexadecimal cast */ |
73317b954 perf probe: Suppo... |
299 300 301 |
tvar->type = strdup(cast); return (tvar->type == NULL) ? -ENOMEM : 0; } |
bcfc08215 perf probe: Remov... |
302 303 |
bsize = dwarf_bitsize(vr_die); if (bsize > 0) { |
124bb83cd perf probe: Add b... |
304 |
/* This is a bitfield */ |
bcfc08215 perf probe: Remov... |
305 306 307 308 309 310 |
boffs = dwarf_bitoffset(vr_die); total = dwarf_bytesize(vr_die); if (boffs < 0 || total < 0) return -ENOENT; ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs, BYTES_TO_BITS(total)); |
124bb83cd perf probe: Add b... |
311 312 |
goto formatted; } |
b55a87ade perf probe: Remov... |
313 314 315 316 317 318 |
if (die_get_real_type(vr_die, &type) == NULL) { pr_warning("Failed to get a type information of %s. ", dwarf_diename(vr_die)); return -ENOENT; } |
4984912eb perf probe: Query... |
319 |
|
b2a3c12b7 perf probe: Suppo... |
320 321 322 |
pr_debug("%s type is %s. ", dwarf_diename(vr_die), dwarf_diename(&type)); |
73317b954 perf probe: Suppo... |
323 324 325 326 327 |
if (cast && strcmp(cast, "string") == 0) { /* String type */ ret = dwarf_tag(&type); if (ret != DW_TAG_pointer_type && ret != DW_TAG_array_type) { pr_warning("Failed to cast into string: " |
0e43e5d22 perf probe: Clean... |
328 329 |
"%s(%s) is not a pointer nor array. ", |
73317b954 perf probe: Suppo... |
330 331 332 |
dwarf_diename(vr_die), dwarf_diename(&type)); return -EINVAL; } |
7ce28b5b5 perf probe: Allow... |
333 334 335 336 337 338 |
if (die_get_real_type(&type, &type) == NULL) { pr_warning("Failed to get a type" " information. "); return -ENOENT; } |
73317b954 perf probe: Suppo... |
339 |
if (ret == DW_TAG_pointer_type) { |
73317b954 perf probe: Suppo... |
340 341 342 |
while (*ref_ptr) ref_ptr = &(*ref_ptr)->next; /* Add new reference with offset +0 */ |
0e60836bb perf probe: Renam... |
343 |
*ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref)); |
73317b954 perf probe: Suppo... |
344 345 346 347 348 349 |
if (*ref_ptr == NULL) { pr_warning("Out of memory error "); return -ENOMEM; } } |
821756335 perf probe: Fix t... |
350 351 |
if (!die_compare_name(&type, "char") && !die_compare_name(&type, "unsigned char")) { |
73317b954 perf probe: Suppo... |
352 |
pr_warning("Failed to cast into string: " |
0e43e5d22 perf probe: Clean... |
353 354 |
"%s is not (unsigned) char *. ", |
73317b954 perf probe: Suppo... |
355 356 357 358 359 360 |
dwarf_diename(vr_die)); return -EINVAL; } tvar->type = strdup(cast); return (tvar->type == NULL) ? -ENOMEM : 0; } |
19f00b011 perf probe: Suppo... |
361 |
if (cast && (strcmp(cast, "u") == 0)) |
925437872 perf probe: Suppo... |
362 |
prefix = 'u'; |
19f00b011 perf probe: Suppo... |
363 |
else if (cast && (strcmp(cast, "s") == 0)) |
925437872 perf probe: Suppo... |
364 365 366 367 |
prefix = 's'; else if (cast && (strcmp(cast, "x") == 0) && probe_type_is_available(PROBE_TYPE_X)) prefix = 'x'; |
19f00b011 perf probe: Suppo... |
368 |
else |
9880ce4a6 perf probe: Use h... |
369 370 |
prefix = die_is_signed_type(&type) ? 's' : probe_type_is_available(PROBE_TYPE_X) ? 'x' : 'u'; |
19f00b011 perf probe: Suppo... |
371 |
|
bcfc08215 perf probe: Remov... |
372 373 |
ret = dwarf_bytesize(&type); if (ret <= 0) |
124bb83cd perf probe: Add b... |
374 375 |
/* No size ... try to use default type */ return 0; |
bcfc08215 perf probe: Remov... |
376 |
ret = BYTES_TO_BITS(ret); |
4984912eb perf probe: Query... |
377 |
|
124bb83cd perf probe: Add b... |
378 379 380 381 382 383 |
/* Check the bitwidth */ if (ret > MAX_BASIC_TYPE_BITS) { pr_info("%s exceeds max-bitwidth. Cut down to %d bits. ", dwarf_diename(&type), MAX_BASIC_TYPE_BITS); ret = MAX_BASIC_TYPE_BITS; |
4984912eb perf probe: Query... |
384 |
} |
925437872 perf probe: Suppo... |
385 |
ret = snprintf(buf, 16, "%c%d", prefix, ret); |
124bb83cd perf probe: Add b... |
386 387 388 389 390 391 392 |
formatted: if (ret < 0 || ret >= 16) { if (ret >= 16) ret = -E2BIG; pr_warning("Failed to convert variable type: %s ", |
c8b5f2c96 tools: Introduce ... |
393 |
str_error_r(-ret, sbuf, sizeof(sbuf))); |
124bb83cd perf probe: Add b... |
394 395 396 397 398 |
return ret; } tvar->type = strdup(buf); if (tvar->type == NULL) return -ENOMEM; |
b55a87ade perf probe: Remov... |
399 |
return 0; |
4984912eb perf probe: Query... |
400 |
} |
b55a87ade perf probe: Remov... |
401 |
static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, |
7df2f3295 perf probe: Add d... |
402 |
struct perf_probe_arg_field *field, |
0e60836bb perf probe: Renam... |
403 |
struct probe_trace_arg_ref **ref_ptr, |
4984912eb perf probe: Query... |
404 |
Dwarf_Die *die_mem) |
7df2f3295 perf probe: Add d... |
405 |
{ |
0e60836bb perf probe: Renam... |
406 |
struct probe_trace_arg_ref *ref = *ref_ptr; |
7df2f3295 perf probe: Add d... |
407 408 |
Dwarf_Die type; Dwarf_Word offs; |
b2a3c12b7 perf probe: Suppo... |
409 |
int ret, tag; |
7df2f3295 perf probe: Add d... |
410 411 412 |
pr_debug("converting %s in %s ", field->name, varname); |
b55a87ade perf probe: Remov... |
413 414 415 416 417 |
if (die_get_real_type(vr_die, &type) == NULL) { pr_warning("Failed to get the type of %s. ", varname); return -ENOENT; } |
b2a3c12b7 perf probe: Suppo... |
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 |
pr_debug2("Var real type: (%x) ", (unsigned)dwarf_dieoffset(&type)); tag = dwarf_tag(&type); if (field->name[0] == '[' && (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { if (field->next) /* Save original type for next field */ memcpy(die_mem, &type, sizeof(*die_mem)); /* Get the type of this array */ if (die_get_real_type(&type, &type) == NULL) { pr_warning("Failed to get the type of %s. ", varname); return -ENOENT; } pr_debug2("Array real type: (%x) ", (unsigned)dwarf_dieoffset(&type)); if (tag == DW_TAG_pointer_type) { |
0e60836bb perf probe: Renam... |
437 |
ref = zalloc(sizeof(struct probe_trace_arg_ref)); |
b2a3c12b7 perf probe: Suppo... |
438 439 440 441 442 443 444 |
if (ref == NULL) return -ENOMEM; if (*ref_ptr) (*ref_ptr)->next = ref; else *ref_ptr = ref; } |
bcfc08215 perf probe: Remov... |
445 |
ref->offset += dwarf_bytesize(&type) * field->index; |
b2a3c12b7 perf probe: Suppo... |
446 447 448 449 450 451 |
if (!field->next) /* Save vr_die for converting types */ memcpy(die_mem, vr_die, sizeof(*die_mem)); goto next; } else if (tag == DW_TAG_pointer_type) { /* Check the pointer and dereference */ |
b55a87ade perf probe: Remov... |
452 453 454 455 456 457 |
if (!field->ref) { pr_err("Semantic error: %s must be referred by '->' ", field->name); return -EINVAL; } |
7df2f3295 perf probe: Add d... |
458 |
/* Get the type pointed by this pointer */ |
b55a87ade perf probe: Remov... |
459 460 461 462 463 |
if (die_get_real_type(&type, &type) == NULL) { pr_warning("Failed to get the type of %s. ", varname); return -ENOENT; } |
12e5a7ae4 perf probe: Corre... |
464 |
/* Verify it is a data structure */ |
7b0295b3d perf probe: Add u... |
465 466 |
tag = dwarf_tag(&type); if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { |
03440c4e5 scripts/spelling.... |
467 468 |
pr_warning("%s is not a data structure nor a union. ", |
7b0295b3d perf probe: Add u... |
469 |
varname); |
b55a87ade perf probe: Remov... |
470 471 |
return -EINVAL; } |
12e5a7ae4 perf probe: Corre... |
472 |
|
0e60836bb perf probe: Renam... |
473 |
ref = zalloc(sizeof(struct probe_trace_arg_ref)); |
e334016f1 perf probe: Remov... |
474 475 |
if (ref == NULL) return -ENOMEM; |
7df2f3295 perf probe: Add d... |
476 477 478 479 480 |
if (*ref_ptr) (*ref_ptr)->next = ref; else *ref_ptr = ref; } else { |
12e5a7ae4 perf probe: Corre... |
481 |
/* Verify it is a data structure */ |
7b0295b3d perf probe: Add u... |
482 |
if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { |
03440c4e5 scripts/spelling.... |
483 484 |
pr_warning("%s is not a data structure nor a union. ", |
7b0295b3d perf probe: Add u... |
485 |
varname); |
b55a87ade perf probe: Remov... |
486 487 |
return -EINVAL; } |
b2a3c12b7 perf probe: Suppo... |
488 |
if (field->name[0] == '[') { |
d939be3ad treewide: Fix typ... |
489 |
pr_err("Semantic error: %s is not a pointer" |
0e43e5d22 perf probe: Clean... |
490 491 |
" nor array. ", varname); |
b2a3c12b7 perf probe: Suppo... |
492 493 |
return -EINVAL; } |
c72738355 perf probe: Fix t... |
494 495 |
/* While prcessing unnamed field, we don't care about this */ if (field->ref && dwarf_diename(vr_die)) { |
b55a87ade perf probe: Remov... |
496 497 498 499 500 501 502 503 504 505 506 |
pr_err("Semantic error: %s must be referred by '.' ", field->name); return -EINVAL; } if (!ref) { pr_warning("Structure on a register is not " "supported yet. "); return -ENOTSUP; } |
7df2f3295 perf probe: Add d... |
507 |
} |
b55a87ade perf probe: Remov... |
508 |
if (die_find_member(&type, field->name, die_mem) == NULL) { |
9ef0438a9 perf probe: Fix typo |
509 510 |
pr_warning("%s(type:%s) has no member %s. ", varname, |
b55a87ade perf probe: Remov... |
511 512 513 |
dwarf_diename(&type), field->name); return -EINVAL; } |
7df2f3295 perf probe: Add d... |
514 515 |
/* Get the offset of the field */ |
7b0295b3d perf probe: Add u... |
516 517 518 519 520 521 522 523 524 525 |
if (tag == DW_TAG_union_type) { offs = 0; } else { ret = die_get_data_member_location(die_mem, &offs); if (ret < 0) { pr_warning("Failed to get the offset of %s. ", field->name); return ret; } |
b55a87ade perf probe: Remov... |
526 |
} |
7df2f3295 perf probe: Add d... |
527 |
ref->offset += (long)offs; |
c72738355 perf probe: Fix t... |
528 529 530 531 |
/* If this member is unnamed, we need to reuse this field */ if (!dwarf_diename(die_mem)) return convert_variable_fields(die_mem, varname, field, &ref, die_mem); |
b2a3c12b7 perf probe: Suppo... |
532 |
next: |
7df2f3295 perf probe: Add d... |
533 534 |
/* Converting next field */ if (field->next) |
b55a87ade perf probe: Remov... |
535 |
return convert_variable_fields(die_mem, field->name, |
de1439d8a perf probe: Suppo... |
536 |
field->next, &ref, die_mem); |
b55a87ade perf probe: Remov... |
537 538 |
else return 0; |
7df2f3295 perf probe: Add d... |
539 |
} |
4ea42b181 perf: Add perf pr... |
540 |
/* Show a variables in kprobe event format */ |
b55a87ade perf probe: Remov... |
541 |
static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) |
4ea42b181 perf: Add perf pr... |
542 |
{ |
4984912eb perf probe: Query... |
543 |
Dwarf_Die die_mem; |
4ea42b181 perf: Add perf pr... |
544 |
int ret; |
b7dcb857c perf probe: Suppo... |
545 546 547 |
pr_debug("Converting variable %s into trace event. ", dwarf_diename(vr_die)); |
804b36068 perf probe: Use e... |
548 |
|
cf6eb489e perf probe: Show ... |
549 |
ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, |
293d5b439 perf probe: Suppo... |
550 |
&pf->sp_die, pf->machine, pf->tvar); |
7d5eaba9b perf probe: Show ... |
551 552 553 554 555 556 557 558 559 |
if (ret == -ENOENT || ret == -EINVAL) { pr_err("Failed to find the location of the '%s' variable at this address. " " Perhaps it has been optimized out. " " Use -V with the --range option to show '%s' location range. ", pf->pvar->var, pf->pvar->var); } else if (ret == -ENOTSUP) |
cf6eb489e perf probe: Show ... |
560 561 |
pr_err("Sorry, we don't support this variable location yet. "); |
0c188a07b perf probe: Fix a... |
562 |
else if (ret == 0 && pf->pvar->field) { |
b55a87ade perf probe: Remov... |
563 564 565 |
ret = convert_variable_fields(vr_die, pf->pvar->var, pf->pvar->field, &pf->tvar->ref, &die_mem); |
4984912eb perf probe: Query... |
566 567 |
vr_die = &die_mem; } |
73317b954 perf probe: Suppo... |
568 569 |
if (ret == 0) ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type); |
804b36068 perf probe: Use e... |
570 |
/* *expr will be cached in libdw. Don't free it. */ |
b55a87ade perf probe: Remov... |
571 |
return ret; |
4ea42b181 perf: Add perf pr... |
572 |
} |
221d06118 perf probe: Fix t... |
573 574 |
/* Find a variable in a scope DIE */ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) |
4ea42b181 perf: Add perf pr... |
575 |
{ |
f182e3e13 perf probe: Avoid... |
576 |
Dwarf_Die vr_die; |
909b0360a perf probe: Use s... |
577 |
char *buf, *ptr; |
f182e3e13 perf probe: Avoid... |
578 |
int ret = 0; |
4ea42b181 perf: Add perf pr... |
579 |
|
da15bd9df perf probe: Suppo... |
580 581 582 |
/* Copy raw parameters */ if (!is_c_varname(pf->pvar->var)) return copy_to_probe_trace_arg(pf->tvar, pf->pvar); |
367e94c10 perf probe: Fix h... |
583 |
|
48481938b perf probe: Suppo... |
584 |
if (pf->pvar->name) |
02b95dadc perf probe: Remov... |
585 |
pf->tvar->name = strdup(pf->pvar->name); |
48481938b perf probe: Suppo... |
586 |
else { |
909b0360a perf probe: Use s... |
587 588 589 |
buf = synthesize_perf_probe_arg(pf->pvar); if (!buf) return -ENOMEM; |
11a1ca355 perf probe: Suppo... |
590 591 592 |
ptr = strchr(buf, ':'); /* Change type separator to _ */ if (ptr) *ptr = '_'; |
909b0360a perf probe: Use s... |
593 |
pf->tvar->name = buf; |
48481938b perf probe: Suppo... |
594 |
} |
02b95dadc perf probe: Remov... |
595 596 |
if (pf->tvar->name == NULL) return -ENOMEM; |
48481938b perf probe: Suppo... |
597 |
|
f182e3e13 perf probe: Avoid... |
598 599 |
pr_debug("Searching '%s' variable in context. ", pf->pvar->var); |
b55a87ade perf probe: Remov... |
600 |
/* Search child die for local variables and parameters. */ |
f182e3e13 perf probe: Avoid... |
601 602 |
if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { /* Search again in global variables */ |
d13855ef1 perf probe: Fix b... |
603 604 |
if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) { |
36d789a4d perf probe: Impro... |
605 606 607 |
pr_warning("Failed to find '%s' in this function. ", pf->pvar->var); |
f182e3e13 perf probe: Avoid... |
608 |
ret = -ENOENT; |
d13855ef1 perf probe: Fix b... |
609 |
} |
b7dcb857c perf probe: Suppo... |
610 |
} |
f66fedcb7 perf probe: Fix r... |
611 |
if (ret >= 0) |
f182e3e13 perf probe: Avoid... |
612 |
ret = convert_variable(&vr_die, pf); |
b7dcb857c perf probe: Suppo... |
613 |
return ret; |
4ea42b181 perf: Add perf pr... |
614 |
} |
cf6eb489e perf probe: Show ... |
615 |
/* Convert subprogram DIE to trace point */ |
576b52372 perf probe: Fix p... |
616 617 |
static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, Dwarf_Addr paddr, bool retprobe, |
6cca13bdf perf probe: Impro... |
618 |
const char *function, |
576b52372 perf probe: Fix p... |
619 |
struct probe_trace_point *tp) |
4ea42b181 perf: Add perf pr... |
620 |
{ |
26b795249 perf probe: Ensur... |
621 |
Dwarf_Addr eaddr, highaddr; |
576b52372 perf probe: Fix p... |
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 |
GElf_Sym sym; const char *symbol; /* Verify the address is correct */ if (dwarf_entrypc(sp_die, &eaddr) != 0) { pr_warning("Failed to get entry address of %s ", dwarf_diename(sp_die)); return -ENOENT; } if (dwarf_highpc(sp_die, &highaddr) != 0) { pr_warning("Failed to get end address of %s ", dwarf_diename(sp_die)); return -ENOENT; } if (paddr > highaddr) { pr_warning("Offset specified is greater than size of %s ", dwarf_diename(sp_die)); return -EINVAL; } |
664fee3dc perf probe: Do no... |
644 |
symbol = dwarf_diename(sp_die); |
576b52372 perf probe: Fix p... |
645 |
if (!symbol) { |
664fee3dc perf probe: Do no... |
646 647 648 649 650 651 652 653 654 |
/* Try to get the symbol name from symtab */ symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); if (!symbol) { pr_warning("Failed to find symbol at 0x%lx ", (unsigned long)paddr); return -ENOENT; } eaddr = sym.st_value; |
576b52372 perf probe: Fix p... |
655 |
} |
664fee3dc perf probe: Do no... |
656 |
tp->offset = (unsigned long)(paddr - eaddr); |
fb7345bbf perf probe: Suppo... |
657 |
tp->address = (unsigned long)paddr; |
576b52372 perf probe: Fix p... |
658 659 660 |
tp->symbol = strdup(symbol); if (!tp->symbol) return -ENOMEM; |
4235b0454 perf probe: Intro... |
661 |
|
04ddd04b0 perf probe: Fix r... |
662 |
/* Return probe must be on the head of a subprogram */ |
cf6eb489e perf probe: Show ... |
663 664 |
if (retprobe) { if (eaddr != paddr) { |
6cca13bdf perf probe: Impro... |
665 666 667 668 669 670 |
pr_warning("Failed to find \"%s%%return\", " " because %s is an inlined function and" " has no return point. ", function, function); |
04ddd04b0 perf probe: Fix r... |
671 672 |
return -EINVAL; } |
cf6eb489e perf probe: Show ... |
673 |
tp->retprobe = true; |
04ddd04b0 perf probe: Fix r... |
674 |
} |
cf6eb489e perf probe: Show ... |
675 676 |
return 0; } |
221d06118 perf probe: Fix t... |
677 678 |
/* Call probe_finder callback with scope DIE */ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) |
cf6eb489e perf probe: Show ... |
679 |
{ |
cf6eb489e perf probe: Show ... |
680 |
Dwarf_Attribute fb_attr; |
4d3b16269 perf probe: Fix t... |
681 |
Dwarf_Frame *frame = NULL; |
cf6eb489e perf probe: Show ... |
682 683 |
size_t nops; int ret; |
221d06118 perf probe: Fix t... |
684 685 686 687 688 689 690 |
if (!sc_die) { pr_err("Caller must pass a scope DIE. Program error. "); return -EINVAL; } /* If not a real subprogram, find a real one */ |
0dbb1cac1 perf probe: Fix f... |
691 |
if (!die_is_func_def(sc_die)) { |
221d06118 perf probe: Fix t... |
692 |
if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { |
d4c537e6b perf probe: Ignor... |
693 694 695 696 697 698 699 700 701 702 703 |
if (die_find_tailfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { pr_warning("Ignoring tail call from %s ", dwarf_diename(&pf->sp_die)); return 0; } else { pr_warning("Failed to find probe point in any " "functions. "); return -ENOENT; } |
cf6eb489e perf probe: Show ... |
704 |
} |
221d06118 perf probe: Fix t... |
705 706 |
} else memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); |
4ea42b181 perf: Add perf pr... |
707 |
|
221d06118 perf probe: Fix t... |
708 709 |
/* Get the frame base attribute/ops from subprogram */ dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); |
d0cb4260f perf probe: Use o... |
710 |
ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); |
a34a98549 perf probe: Suppo... |
711 |
if (ret <= 0 || nops == 0) { |
804b36068 perf probe: Use e... |
712 |
pf->fb_ops = NULL; |
7752f1b09 perf probe: Don't... |
713 |
#if _ELFUTILS_PREREQ(0, 142) |
a34a98549 perf probe: Suppo... |
714 |
} else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && |
270bde1e7 perf probe: Searc... |
715 716 717 |
(pf->cfi_eh != NULL || pf->cfi_dbg != NULL)) { if ((dwarf_cfi_addrframe(pf->cfi_eh, pf->addr, &frame) != 0 && (dwarf_cfi_addrframe(pf->cfi_dbg, pf->addr, &frame) != 0)) || |
b55a87ade perf probe: Remov... |
718 |
dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { |
0e43e5d22 perf probe: Clean... |
719 720 |
pr_warning("Failed to get call frame on 0x%jx ", |
b55a87ade perf probe: Remov... |
721 |
(uintmax_t)pf->addr); |
4d3b16269 perf probe: Fix t... |
722 723 |
free(frame); return -ENOENT; |
b55a87ade perf probe: Remov... |
724 |
} |
7752f1b09 perf probe: Don't... |
725 |
#endif |
a34a98549 perf probe: Suppo... |
726 |
} |
804b36068 perf probe: Use e... |
727 |
|
cf6eb489e perf probe: Show ... |
728 |
/* Call finder's callback handler */ |
4d3b16269 perf probe: Fix t... |
729 |
ret = pf->callback(sc_die, pf); |
804b36068 perf probe: Use e... |
730 |
|
4d3b16269 perf probe: Fix t... |
731 732 |
/* Since *pf->fb_ops can be a part of frame. we should free it here. */ free(frame); |
804b36068 perf probe: Use e... |
733 |
pf->fb_ops = NULL; |
cf6eb489e perf probe: Show ... |
734 735 |
return ret; |
4ea42b181 perf: Add perf pr... |
736 |
} |
221d06118 perf probe: Fix t... |
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 |
struct find_scope_param { const char *function; const char *file; int line; int diff; Dwarf_Die *die_mem; bool found; }; static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) { struct find_scope_param *fsp = data; const char *file; int lno; /* Skip if declared file name does not match */ if (fsp->file) { file = dwarf_decl_file(fn_die); if (!file || strcmp(fsp->file, file) != 0) return 0; } /* If the function name is given, that's what user expects */ if (fsp->function) { |
4c8593512 perf probe: Suppo... |
760 |
if (die_match_name(fn_die, fsp->function)) { |
221d06118 perf probe: Fix t... |
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 |
memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); fsp->found = true; return 1; } } else { /* With the line number, find the nearest declared DIE */ dwarf_decl_line(fn_die, &lno); if (lno < fsp->line && fsp->diff > fsp->line - lno) { /* Keep a candidate and continue */ fsp->diff = fsp->line - lno; memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); fsp->found = true; } } return 0; } /* Find an appropriate scope fits to given conditions */ static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) { struct find_scope_param fsp = { .function = pf->pev->point.function, .file = pf->fname, .line = pf->lno, .diff = INT_MAX, .die_mem = die_mem, .found = false, }; cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); return fsp.found ? die_mem : NULL; } |
4cc9cec63 perf probe: Intro... |
794 795 |
static int probe_point_line_walker(const char *fname, int lineno, Dwarf_Addr addr, void *data) |
4ea42b181 perf: Add perf pr... |
796 |
{ |
4cc9cec63 perf probe: Intro... |
797 |
struct probe_finder *pf = data; |
221d06118 perf probe: Fix t... |
798 |
Dwarf_Die *sc_die, die_mem; |
4cc9cec63 perf probe: Intro... |
799 |
int ret; |
4ea42b181 perf: Add perf pr... |
800 |
|
4cc9cec63 perf probe: Intro... |
801 802 |
if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) return 0; |
4ea42b181 perf: Add perf pr... |
803 |
|
4cc9cec63 perf probe: Intro... |
804 |
pf->addr = addr; |
221d06118 perf probe: Fix t... |
805 806 807 808 809 810 811 812 |
sc_die = find_best_scope(pf, &die_mem); if (!sc_die) { pr_warning("Failed to find scope of probe point. "); return -ENOENT; } ret = call_probe_finder(sc_die, pf); |
b0ef07324 perf/probes: Supp... |
813 |
|
4cc9cec63 perf probe: Intro... |
814 |
/* Continue if no error, because the line will be in inline function */ |
fbee632d0 perf probe: Fix e... |
815 |
return ret < 0 ? ret : 0; |
4cc9cec63 perf probe: Intro... |
816 |
} |
804b36068 perf probe: Use e... |
817 |
|
4cc9cec63 perf probe: Intro... |
818 819 820 821 |
/* Find probe point from its line number */ static int find_probe_point_by_line(struct probe_finder *pf) { return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf); |
4ea42b181 perf: Add perf pr... |
822 |
} |
2a9c8c360 perf probe: Add l... |
823 |
/* Find lines which match lazy pattern */ |
5a62257a3 perf probe: Repla... |
824 |
static int find_lazy_match_lines(struct intlist *list, |
2a9c8c360 perf probe: Add l... |
825 826 |
const char *fname, const char *pat) { |
f50c2169b perf probe: Rewri... |
827 828 829 830 831 |
FILE *fp; char *line = NULL; size_t line_len; ssize_t len; int count = 0, linenum = 1; |
5f03cba41 perf probe: Make ... |
832 |
char sbuf[STRERR_BUFSIZE]; |
f50c2169b perf probe: Rewri... |
833 834 835 |
fp = fopen(fname, "r"); if (!fp) { |
5f03cba41 perf probe: Make ... |
836 837 |
pr_warning("Failed to open %s: %s ", fname, |
c8b5f2c96 tools: Introduce ... |
838 |
str_error_r(errno, sbuf, sizeof(sbuf))); |
b448c4b61 perf probe: Fix s... |
839 |
return -errno; |
b55a87ade perf probe: Remov... |
840 |
} |
f50c2169b perf probe: Rewri... |
841 |
while ((len = getline(&line, &line_len, fp)) > 0) { |
b448c4b61 perf probe: Fix s... |
842 |
|
f50c2169b perf probe: Rewri... |
843 844 845 846 847 |
if (line[len - 1] == ' ') line[len - 1] = '\0'; if (strlazymatch(line, pat)) { |
5a62257a3 perf probe: Repla... |
848 |
intlist__add(list, linenum); |
f50c2169b perf probe: Rewri... |
849 |
count++; |
2a9c8c360 perf probe: Add l... |
850 |
} |
f50c2169b perf probe: Rewri... |
851 |
linenum++; |
2a9c8c360 perf probe: Add l... |
852 |
} |
f50c2169b perf probe: Rewri... |
853 854 855 856 857 858 859 860 861 862 |
if (ferror(fp)) count = -errno; free(line); fclose(fp); if (count == 0) pr_debug("No matched lines found in %s. ", fname); return count; |
2a9c8c360 perf probe: Add l... |
863 |
} |
4cc9cec63 perf probe: Intro... |
864 865 866 867 |
static int probe_point_lazy_walker(const char *fname, int lineno, Dwarf_Addr addr, void *data) { struct probe_finder *pf = data; |
221d06118 perf probe: Fix t... |
868 |
Dwarf_Die *sc_die, die_mem; |
4cc9cec63 perf probe: Intro... |
869 |
int ret; |
5a62257a3 perf probe: Repla... |
870 |
if (!intlist__has_entry(pf->lcache, lineno) || |
4cc9cec63 perf probe: Intro... |
871 872 873 874 875 876 877 |
strtailcmp(fname, pf->fname) != 0) return 0; pr_debug("Probe line found: line:%d addr:0x%llx ", lineno, (unsigned long long)addr); pf->addr = addr; |
221d06118 perf probe: Fix t... |
878 879 880 881 882 883 884 885 886 |
pf->lno = lineno; sc_die = find_best_scope(pf, &die_mem); if (!sc_die) { pr_warning("Failed to find scope of probe point. "); return -ENOENT; } ret = call_probe_finder(sc_die, pf); |
4cc9cec63 perf probe: Intro... |
887 888 889 890 891 |
/* * Continue if no error, because the lazy pattern will match * to other lines */ |
5e814dd59 perf probe: Clean... |
892 |
return ret < 0 ? ret : 0; |
4cc9cec63 perf probe: Intro... |
893 |
} |
2a9c8c360 perf probe: Add l... |
894 |
/* Find probe points from lazy pattern */ |
b55a87ade perf probe: Remov... |
895 |
static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) |
2a9c8c360 perf probe: Add l... |
896 |
{ |
b55a87ade perf probe: Remov... |
897 |
int ret = 0; |
09ed8975c perf probe: Find ... |
898 |
char *fpath; |
2a9c8c360 perf probe: Add l... |
899 |
|
5a62257a3 perf probe: Repla... |
900 |
if (intlist__empty(pf->lcache)) { |
09ed8975c perf probe: Find ... |
901 902 903 904 905 906 907 908 909 |
const char *comp_dir; comp_dir = cu_get_comp_dir(&pf->cu_die); ret = get_real_path(pf->fname, comp_dir, &fpath); if (ret < 0) { pr_warning("Failed to find source file path. "); return ret; } |
2a9c8c360 perf probe: Add l... |
910 |
/* Matching lazy line pattern */ |
09ed8975c perf probe: Find ... |
911 |
ret = find_lazy_match_lines(pf->lcache, fpath, |
4235b0454 perf probe: Intro... |
912 |
pf->pev->point.lazy_line); |
09ed8975c perf probe: Find ... |
913 |
free(fpath); |
f50c2169b perf probe: Rewri... |
914 |
if (ret <= 0) |
b55a87ade perf probe: Remov... |
915 |
return ret; |
2a9c8c360 perf probe: Add l... |
916 |
} |
4cc9cec63 perf probe: Intro... |
917 |
return die_walk_lines(sp_die, probe_point_lazy_walker, pf); |
2a9c8c360 perf probe: Add l... |
918 |
} |
e47392bf9 perf uprobe: Skip... |
919 920 921 922 923 924 925 926 927 |
static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf) { struct perf_probe_point *pp = &pf->pev->point; /* Not uprobe? */ if (!pf->pev->uprobes) return; /* Compiled with optimization? */ |
6243b9dc4 perf probe: Move ... |
928 |
if (die_is_optimized_target(&pf->cu_die)) |
e47392bf9 perf uprobe: Skip... |
929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 |
return; /* Don't know entrypc? */ if (!pf->addr) return; /* Only FUNC and FUNC@SRC are eligible. */ if (!pp->function || pp->line || pp->retprobe || pp->lazy_line || pp->offset || pp->abs_address) return; /* Not interested in func parameter? */ if (!perf_probe_with_var(pf->pev)) return; pr_info("Target program is compiled without optimization. Skipping prologue. " "Probe on address 0x%" PRIx64 " to force probing at the function entry. ", pf->addr); |
6243b9dc4 perf probe: Move ... |
950 |
die_skip_prologue(sp_die, &pf->cu_die, &pf->addr); |
e47392bf9 perf uprobe: Skip... |
951 |
} |
e92b85e1f perf probe: Use l... |
952 953 |
static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) { |
db0d2c642 perf probe: Searc... |
954 |
struct probe_finder *pf = data; |
4235b0454 perf probe: Intro... |
955 |
struct perf_probe_point *pp = &pf->pev->point; |
b55a87ade perf probe: Remov... |
956 |
Dwarf_Addr addr; |
db0d2c642 perf probe: Searc... |
957 |
int ret; |
e92b85e1f perf probe: Use l... |
958 |
|
2a9c8c360 perf probe: Add l... |
959 |
if (pp->lazy_line) |
db0d2c642 perf probe: Searc... |
960 |
ret = find_probe_point_lazy(in_die, pf); |
2a9c8c360 perf probe: Add l... |
961 962 |
else { /* Get probe address */ |
b55a87ade perf probe: Remov... |
963 |
if (dwarf_entrypc(in_die, &addr) != 0) { |
0e43e5d22 perf probe: Clean... |
964 965 |
pr_warning("Failed to get entry address of %s. ", |
b55a87ade perf probe: Remov... |
966 |
dwarf_diename(in_die)); |
db0d2c642 perf probe: Searc... |
967 |
return -ENOENT; |
b55a87ade perf probe: Remov... |
968 |
} |
0ad45b33c perf probe: Skip ... |
969 970 971 972 973 974 |
if (addr == 0) { pr_debug("%s has no valid entry address. skipped. ", dwarf_diename(in_die)); return -ENOENT; } |
b55a87ade perf probe: Remov... |
975 |
pf->addr = addr; |
2a9c8c360 perf probe: Add l... |
976 977 978 979 |
pf->addr += pp->offset; pr_debug("found inline addr: 0x%jx ", (uintmax_t)pf->addr); |
db0d2c642 perf probe: Searc... |
980 |
ret = call_probe_finder(in_die, pf); |
2a9c8c360 perf probe: Add l... |
981 |
} |
e92b85e1f perf probe: Use l... |
982 |
|
db0d2c642 perf probe: Searc... |
983 |
return ret; |
e92b85e1f perf probe: Use l... |
984 |
} |
804b36068 perf probe: Use e... |
985 |
|
db0d2c642 perf probe: Searc... |
986 987 988 989 990 |
/* Callback parameter with return value for libdw */ struct dwarf_callback_param { void *data; int retval; }; |
4ea42b181 perf: Add perf pr... |
991 |
/* Search function from function name */ |
e92b85e1f perf probe: Use l... |
992 |
static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) |
4ea42b181 perf: Add perf pr... |
993 |
{ |
b55a87ade perf probe: Remov... |
994 995 |
struct dwarf_callback_param *param = data; struct probe_finder *pf = param->data; |
4235b0454 perf probe: Intro... |
996 |
struct perf_probe_point *pp = &pf->pev->point; |
4ea42b181 perf: Add perf pr... |
997 |
|
e92b85e1f perf probe: Use l... |
998 |
/* Check tag and diename */ |
0dbb1cac1 perf probe: Fix f... |
999 |
if (!die_is_func_def(sp_die) || |
4c8593512 perf probe: Suppo... |
1000 |
!die_match_name(sp_die, pp->function)) |
b55a87ade perf probe: Remov... |
1001 |
return DWARF_CB_OK; |
e92b85e1f perf probe: Use l... |
1002 |
|
7d21635ac perf probe: Fix t... |
1003 1004 1005 |
/* Check declared file */ if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die))) return DWARF_CB_OK; |
f8da4b515 perf probe: Ignor... |
1006 1007 1008 |
pr_debug("Matched function: %s [%lx] ", dwarf_diename(sp_die), (unsigned long)dwarf_dieoffset(sp_die)); |
2a9c8c360 perf probe: Add l... |
1009 |
pf->fname = dwarf_decl_file(sp_die); |
e92b85e1f perf probe: Use l... |
1010 |
if (pp->line) { /* Function relative line */ |
e92b85e1f perf probe: Use l... |
1011 1012 |
dwarf_decl_line(sp_die, &pf->lno); pf->lno += pp->line; |
b55a87ade perf probe: Remov... |
1013 |
param->retval = find_probe_point_by_line(pf); |
e1ecbbc3f perf probe: Fix t... |
1014 1015 1016 |
} else if (die_is_func_instance(sp_die)) { /* Instances always have the entry address */ dwarf_entrypc(sp_die, &pf->addr); |
0ad45b33c perf probe: Skip ... |
1017 1018 1019 1020 1021 1022 |
/* But in some case the entry address is 0 */ if (pf->addr == 0) { pr_debug("%s has no entry PC. Skipped ", dwarf_diename(sp_die)); param->retval = 0; |
e92b85e1f perf probe: Use l... |
1023 |
/* Real function */ |
0ad45b33c perf probe: Skip ... |
1024 |
} else if (pp->lazy_line) |
b55a87ade perf probe: Remov... |
1025 |
param->retval = find_probe_point_lazy(sp_die, pf); |
2a9c8c360 perf probe: Add l... |
1026 |
else { |
e47392bf9 perf uprobe: Skip... |
1027 |
skip_prologue(sp_die, pf); |
2a9c8c360 perf probe: Add l... |
1028 1029 |
pf->addr += pp->offset; /* TODO: Check the address in this function */ |
cf6eb489e perf probe: Show ... |
1030 |
param->retval = call_probe_finder(sp_die, pf); |
2a9c8c360 perf probe: Add l... |
1031 |
} |
4c8593512 perf probe: Suppo... |
1032 |
} else if (!probe_conf.no_inlines) { |
e92b85e1f perf probe: Use l... |
1033 |
/* Inlined function: search instances */ |
db0d2c642 perf probe: Searc... |
1034 1035 |
param->retval = die_walk_instances(sp_die, probe_point_inline_cb, (void *)pf); |
4c8593512 perf probe: Suppo... |
1036 |
/* This could be a non-existed inline definition */ |
f8da4b515 perf probe: Ignor... |
1037 |
if (param->retval == -ENOENT) |
4c8593512 perf probe: Suppo... |
1038 1039 1040 1041 1042 1043 1044 1045 |
param->retval = 0; } /* We need to find other candidates */ if (strisglob(pp->function) && param->retval >= 0) { param->retval = 0; /* We have to clear the result */ return DWARF_CB_OK; } |
e92b85e1f perf probe: Use l... |
1046 |
|
b55a87ade perf probe: Remov... |
1047 |
return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ |
4ea42b181 perf: Add perf pr... |
1048 |
} |
b55a87ade perf probe: Remov... |
1049 |
static int find_probe_point_by_func(struct probe_finder *pf) |
4ea42b181 perf: Add perf pr... |
1050 |
{ |
b55a87ade perf probe: Remov... |
1051 1052 1053 1054 |
struct dwarf_callback_param _param = {.data = (void *)pf, .retval = 0}; dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); return _param.retval; |
4ea42b181 perf: Add perf pr... |
1055 |
} |
cd25f8bc2 perf probe: Add f... |
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 |
struct pubname_callback_param { char *function; char *file; Dwarf_Die *cu_die; Dwarf_Die *sp_die; int found; }; static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) { struct pubname_callback_param *param = data; if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) { if (dwarf_tag(param->sp_die) != DW_TAG_subprogram) return DWARF_CB_OK; |
4c8593512 perf probe: Suppo... |
1071 |
if (die_match_name(param->sp_die, param->function)) { |
cd25f8bc2 perf probe: Add f... |
1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 |
if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die)) return DWARF_CB_OK; if (param->file && strtailcmp(param->file, dwarf_decl_file(param->sp_die))) return DWARF_CB_OK; param->found = 1; return DWARF_CB_ABORT; } } return DWARF_CB_OK; } |
270bde1e7 perf probe: Searc... |
1086 |
static int debuginfo__find_probe_location(struct debuginfo *dbg, |
ff7417835 perf probe: Intro... |
1087 |
struct probe_finder *pf) |
4ea42b181 perf: Add perf pr... |
1088 |
{ |
cf6eb489e perf probe: Show ... |
1089 |
struct perf_probe_point *pp = &pf->pev->point; |
804b36068 perf probe: Use e... |
1090 1091 1092 |
Dwarf_Off off, noff; size_t cuhl; Dwarf_Die *diep; |
b55a87ade perf probe: Remov... |
1093 |
int ret = 0; |
804b36068 perf probe: Use e... |
1094 |
|
804b36068 perf probe: Use e... |
1095 |
off = 0; |
5a62257a3 perf probe: Repla... |
1096 1097 1098 |
pf->lcache = intlist__new(NULL); if (!pf->lcache) return -ENOMEM; |
cd25f8bc2 perf probe: Add f... |
1099 1100 |
/* Fastpath: lookup by function name from .debug_pubnames section */ |
4c8593512 perf probe: Suppo... |
1101 |
if (pp->function && !strisglob(pp->function)) { |
cd25f8bc2 perf probe: Add f... |
1102 1103 1104 1105 1106 |
struct pubname_callback_param pubname_param = { .function = pp->function, .file = pp->file, .cu_die = &pf->cu_die, .sp_die = &pf->sp_die, |
2b348a779 perf probe: Fix t... |
1107 |
.found = 0, |
cd25f8bc2 perf probe: Add f... |
1108 1109 1110 1111 |
}; struct dwarf_callback_param probe_param = { .data = pf, }; |
316c7136f perf tools: Finis... |
1112 |
dwarf_getpubnames(dbg->dbg, pubname_search_cb, |
ff7417835 perf probe: Intro... |
1113 |
&pubname_param, 0); |
cd25f8bc2 perf probe: Add f... |
1114 1115 1116 1117 1118 1119 |
if (pubname_param.found) { ret = probe_point_search_cb(&pf->sp_die, &probe_param); if (ret) goto found; } } |
804b36068 perf probe: Use e... |
1120 |
/* Loop on CUs (Compilation Unit) */ |
316c7136f perf tools: Finis... |
1121 |
while (!dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { |
4ea42b181 perf: Add perf pr... |
1122 |
/* Get the DIE(Debugging Information Entry) of this CU */ |
316c7136f perf tools: Finis... |
1123 |
diep = dwarf_offdie(dbg->dbg, off + cuhl, &pf->cu_die); |
804b36068 perf probe: Use e... |
1124 1125 |
if (!diep) continue; |
4ea42b181 perf: Add perf pr... |
1126 1127 1128 |
/* Check if target file is included. */ if (pp->file) |
cf6eb489e perf probe: Show ... |
1129 |
pf->fname = cu_find_realpath(&pf->cu_die, pp->file); |
804b36068 perf probe: Use e... |
1130 |
else |
cf6eb489e perf probe: Show ... |
1131 |
pf->fname = NULL; |
4ea42b181 perf: Add perf pr... |
1132 |
|
cf6eb489e perf probe: Show ... |
1133 |
if (!pp->file || pf->fname) { |
4ea42b181 perf: Add perf pr... |
1134 |
if (pp->function) |
cf6eb489e perf probe: Show ... |
1135 |
ret = find_probe_point_by_func(pf); |
2a9c8c360 perf probe: Add l... |
1136 |
else if (pp->lazy_line) |
f19e80c64 perf probe: Fix s... |
1137 |
ret = find_probe_point_lazy(&pf->cu_die, pf); |
b0ef07324 perf/probes: Supp... |
1138 |
else { |
cf6eb489e perf probe: Show ... |
1139 1140 |
pf->lno = pp->line; ret = find_probe_point_by_line(pf); |
b0ef07324 perf/probes: Supp... |
1141 |
} |
8635bf6ea perf probe: Remov... |
1142 |
if (ret < 0) |
fbee632d0 perf probe: Fix e... |
1143 |
break; |
4ea42b181 perf: Add perf pr... |
1144 |
} |
804b36068 perf probe: Use e... |
1145 |
off = noff; |
4ea42b181 perf: Add perf pr... |
1146 |
} |
cd25f8bc2 perf probe: Add f... |
1147 1148 |
found: |
5a62257a3 perf probe: Repla... |
1149 1150 |
intlist__delete(pf->lcache); pf->lcache = NULL; |
4ea42b181 perf: Add perf pr... |
1151 |
|
cf6eb489e perf probe: Show ... |
1152 1153 |
return ret; } |
270bde1e7 perf probe: Searc... |
1154 1155 1156 1157 1158 |
/* Find probe points from debuginfo */ static int debuginfo__find_probes(struct debuginfo *dbg, struct probe_finder *pf) { int ret = 0; |
270bde1e7 perf probe: Searc... |
1159 1160 |
Elf *elf; GElf_Ehdr ehdr; |
270bde1e7 perf probe: Searc... |
1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 |
if (pf->cfi_eh || pf->cfi_dbg) return debuginfo__find_probe_location(dbg, pf); /* Get the call frame information from this dwarf */ elf = dwarf_getelf(dbg->dbg); if (elf == NULL) return -EINVAL; if (gelf_getehdr(elf, &ehdr) == NULL) return -EINVAL; |
293d5b439 perf probe: Suppo... |
1172 1173 1174 1175 1176 1177 1178 1179 1180 |
pf->machine = ehdr.e_machine; #if _ELFUTILS_PREREQ(0, 142) do { GElf_Shdr shdr; if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) && shdr.sh_type == SHT_PROGBITS) pf->cfi_eh = dwarf_getcfi_elf(elf); |
270bde1e7 perf probe: Searc... |
1181 |
|
293d5b439 perf probe: Suppo... |
1182 1183 |
pf->cfi_dbg = dwarf_getcfi(dbg->dbg); } while (0); |
270bde1e7 perf probe: Searc... |
1184 1185 1186 1187 1188 |
#endif ret = debuginfo__find_probe_location(dbg, pf); return ret; } |
7969ec772 perf probe: Suppo... |
1189 1190 1191 |
struct local_vars_finder { struct probe_finder *pf; struct perf_probe_arg *args; |
f8bffbf12 perf probe: Suppo... |
1192 |
bool vars; |
7969ec772 perf probe: Suppo... |
1193 1194 1195 1196 1197 1198 1199 1200 1201 |
int max_args; int nargs; int ret; }; /* Collect available variables in this scope */ static int copy_variables_cb(Dwarf_Die *die_mem, void *data) { struct local_vars_finder *vf = data; |
3d918a12a perf probe: Find ... |
1202 |
struct probe_finder *pf = vf->pf; |
7969ec772 perf probe: Suppo... |
1203 1204 1205 1206 |
int tag; tag = dwarf_tag(die_mem); if (tag == DW_TAG_formal_parameter || |
f8bffbf12 perf probe: Suppo... |
1207 |
(tag == DW_TAG_variable && vf->vars)) { |
7969ec772 perf probe: Suppo... |
1208 |
if (convert_variable_location(die_mem, vf->pf->addr, |
3d918a12a perf probe: Find ... |
1209 |
vf->pf->fb_ops, &pf->sp_die, |
293d5b439 perf probe: Suppo... |
1210 |
pf->machine, NULL) == 0) { |
7969ec772 perf probe: Suppo... |
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 |
vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem); if (vf->args[vf->nargs].var == NULL) { vf->ret = -ENOMEM; return DIE_FIND_CB_END; } pr_debug(" %s", vf->args[vf->nargs].var); vf->nargs++; } } if (dwarf_haspc(die_mem, vf->pf->addr)) return DIE_FIND_CB_CONTINUE; else return DIE_FIND_CB_SIBLING; } static int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf, struct perf_probe_arg *args) { Dwarf_Die die_mem; int i; int n = 0; |
f8bffbf12 perf probe: Suppo... |
1233 |
struct local_vars_finder vf = {.pf = pf, .args = args, .vars = false, |
7969ec772 perf probe: Suppo... |
1234 1235 1236 1237 |
.max_args = MAX_PROBE_ARGS, .ret = 0}; for (i = 0; i < pf->pev->nargs; i++) { /* var never be NULL */ |
f8bffbf12 perf probe: Suppo... |
1238 1239 1240 |
if (strcmp(pf->pev->args[i].var, PROBE_ARG_VARS) == 0) vf.vars = true; else if (strcmp(pf->pev->args[i].var, PROBE_ARG_PARAMS) != 0) { |
7969ec772 perf probe: Suppo... |
1241 1242 1243 |
/* Copy normal argument */ args[n] = pf->pev->args[i]; n++; |
f8bffbf12 perf probe: Suppo... |
1244 |
continue; |
7969ec772 perf probe: Suppo... |
1245 |
} |
f8bffbf12 perf probe: Suppo... |
1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 |
pr_debug("Expanding %s into:", pf->pev->args[i].var); vf.nargs = n; /* Special local variables */ die_find_child(sc_die, copy_variables_cb, (void *)&vf, &die_mem); pr_debug(" (%d) ", vf.nargs - n); if (vf.ret < 0) return vf.ret; n = vf.nargs; |
7969ec772 perf probe: Suppo... |
1256 1257 1258 |
} return n; } |
cf6eb489e perf probe: Show ... |
1259 |
/* Add a found probe point into trace event list */ |
221d06118 perf probe: Fix t... |
1260 |
static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) |
cf6eb489e perf probe: Show ... |
1261 1262 1263 |
{ struct trace_event_finder *tf = container_of(pf, struct trace_event_finder, pf); |
6cca13bdf perf probe: Impro... |
1264 |
struct perf_probe_point *pp = &pf->pev->point; |
cf6eb489e perf probe: Show ... |
1265 |
struct probe_trace_event *tev; |
092b1f0b5 perf probe: Clear... |
1266 |
struct perf_probe_arg *args = NULL; |
cf6eb489e perf probe: Show ... |
1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 |
int ret, i; /* Check number of tevs */ if (tf->ntevs == tf->max_tevs) { pr_warning("Too many( > %d) probe point found. ", tf->max_tevs); return -ERANGE; } tev = &tf->tevs[tf->ntevs++]; |
221d06118 perf probe: Fix t... |
1277 |
/* Trace point should be converted from subprogram DIE */ |
576b52372 perf probe: Fix p... |
1278 |
ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr, |
6cca13bdf perf probe: Impro... |
1279 |
pp->retprobe, pp->function, &tev->point); |
cf6eb489e perf probe: Show ... |
1280 |
if (ret < 0) |
092b1f0b5 perf probe: Clear... |
1281 |
goto end; |
cf6eb489e perf probe: Show ... |
1282 |
|
4c8593512 perf probe: Suppo... |
1283 |
tev->point.realname = strdup(dwarf_diename(sc_die)); |
092b1f0b5 perf probe: Clear... |
1284 1285 1286 1287 |
if (!tev->point.realname) { ret = -ENOMEM; goto end; } |
4c8593512 perf probe: Suppo... |
1288 |
|
cf6eb489e perf probe: Show ... |
1289 1290 1291 |
pr_debug("Probe point found: %s+%lu ", tev->point.symbol, tev->point.offset); |
7969ec772 perf probe: Suppo... |
1292 1293 |
/* Expand special probe argument if exist */ args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS); |
092b1f0b5 perf probe: Clear... |
1294 1295 1296 1297 |
if (args == NULL) { ret = -ENOMEM; goto end; } |
7969ec772 perf probe: Suppo... |
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 |
ret = expand_probe_args(sc_die, pf, args); if (ret < 0) goto end; tev->nargs = ret; tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); if (tev->args == NULL) { ret = -ENOMEM; goto end; } /* Find each argument */ for (i = 0; i < tev->nargs; i++) { pf->pvar = &args[i]; |
cf6eb489e perf probe: Show ... |
1313 |
pf->tvar = &tev->args[i]; |
221d06118 perf probe: Fix t... |
1314 1315 |
/* Variable should be found from scope DIE */ ret = find_variable(sc_die, pf); |
cf6eb489e perf probe: Show ... |
1316 |
if (ret != 0) |
7969ec772 perf probe: Suppo... |
1317 |
break; |
cf6eb489e perf probe: Show ... |
1318 |
} |
7969ec772 perf probe: Suppo... |
1319 |
end: |
092b1f0b5 perf probe: Clear... |
1320 1321 1322 1323 |
if (ret) { clear_probe_trace_event(tev); tf->ntevs--; } |
7969ec772 perf probe: Suppo... |
1324 1325 |
free(args); return ret; |
cf6eb489e perf probe: Show ... |
1326 1327 1328 |
} /* Find probe_trace_events specified by perf_probe_event from debuginfo */ |
316c7136f perf tools: Finis... |
1329 |
int debuginfo__find_trace_events(struct debuginfo *dbg, |
ff7417835 perf probe: Intro... |
1330 |
struct perf_probe_event *pev, |
ddb2f58f9 perf probe: Intro... |
1331 |
struct probe_trace_event **tevs) |
cf6eb489e perf probe: Show ... |
1332 1333 1334 |
{ struct trace_event_finder tf = { .pf = {.pev = pev, .callback = add_probe_trace_event}, |
ddb2f58f9 perf probe: Intro... |
1335 |
.max_tevs = probe_conf.max_probes, .mod = dbg->mod}; |
0196e787c perf probe: Fix m... |
1336 |
int ret, i; |
cf6eb489e perf probe: Show ... |
1337 1338 |
/* Allocate result tevs array */ |
ddb2f58f9 perf probe: Intro... |
1339 |
*tevs = zalloc(sizeof(struct probe_trace_event) * tf.max_tevs); |
cf6eb489e perf probe: Show ... |
1340 1341 1342 1343 1344 |
if (*tevs == NULL) return -ENOMEM; tf.tevs = *tevs; tf.ntevs = 0; |
316c7136f perf tools: Finis... |
1345 |
ret = debuginfo__find_probes(dbg, &tf.pf); |
cf6eb489e perf probe: Show ... |
1346 |
if (ret < 0) { |
0196e787c perf probe: Fix m... |
1347 1348 |
for (i = 0; i < tf.ntevs; i++) clear_probe_trace_event(&tf.tevs[i]); |
046625231 perf tools: Intro... |
1349 |
zfree(tevs); |
cf6eb489e perf probe: Show ... |
1350 1351 1352 1353 1354 |
return ret; } return (ret < 0) ? ret : tf.ntevs; } |
cf6eb489e perf probe: Show ... |
1355 1356 1357 1358 1359 |
/* Collect available variables in this scope */ static int collect_variables_cb(Dwarf_Die *die_mem, void *data) { struct available_var_finder *af = data; struct variable_list *vl; |
bf4d5f25c perf probe: Check... |
1360 |
struct strbuf buf = STRBUF_INIT; |
cf6eb489e perf probe: Show ... |
1361 1362 1363 1364 1365 1366 1367 1368 |
int tag, ret; vl = &af->vls[af->nvls - 1]; tag = dwarf_tag(die_mem); if (tag == DW_TAG_formal_parameter || tag == DW_TAG_variable) { ret = convert_variable_location(die_mem, af->pf.addr, |
3d918a12a perf probe: Find ... |
1369 |
af->pf.fb_ops, &af->pf.sp_die, |
293d5b439 perf probe: Suppo... |
1370 |
af->pf.machine, NULL); |
349e8d261 perf probe: Add -... |
1371 1372 1373 |
if (ret == 0 || ret == -ERANGE) { int ret2; bool externs = !af->child; |
fb9596d17 perf probe: Remov... |
1374 |
|
bf4d5f25c perf probe: Check... |
1375 1376 |
if (strbuf_init(&buf, 64) < 0) goto error; |
349e8d261 perf probe: Add -... |
1377 1378 |
if (probe_conf.show_location_range) { |
bf4d5f25c perf probe: Check... |
1379 1380 1381 1382 1383 1384 1385 |
if (!externs) ret2 = strbuf_add(&buf, ret ? "[INV]\t" : "[VAL]\t", 6); else ret2 = strbuf_add(&buf, "[EXT]\t", 6); if (ret2) goto error; |
349e8d261 perf probe: Add -... |
1386 1387 1388 1389 1390 1391 |
} ret2 = die_get_varname(die_mem, &buf); if (!ret2 && probe_conf.show_location_range && !externs) { |
bf4d5f25c perf probe: Check... |
1392 1393 |
if (strbuf_addch(&buf, '\t') < 0) goto error; |
349e8d261 perf probe: Add -... |
1394 1395 1396 1397 1398 1399 1400 |
ret2 = die_get_var_range(&af->pf.sp_die, die_mem, &buf); } pr_debug("Add new var: %s ", buf.buf); if (ret2 == 0) { |
fb9596d17 perf probe: Remov... |
1401 1402 |
strlist__add(vl->vars, strbuf_detach(&buf, NULL)); |
bf4d5f25c perf probe: Check... |
1403 1404 |
} strbuf_release(&buf); |
cf6eb489e perf probe: Show ... |
1405 1406 |
} } |
fb8c5a56c perf probe: Show ... |
1407 |
if (af->child && dwarf_haspc(die_mem, af->pf.addr)) |
cf6eb489e perf probe: Show ... |
1408 1409 1410 |
return DIE_FIND_CB_CONTINUE; else return DIE_FIND_CB_SIBLING; |
bf4d5f25c perf probe: Check... |
1411 1412 1413 1414 1415 |
error: strbuf_release(&buf); pr_debug("Error in strbuf "); return DIE_FIND_CB_END; |
cf6eb489e perf probe: Show ... |
1416 1417 1418 |
} /* Add a found vars into available variables list */ |
221d06118 perf probe: Fix t... |
1419 |
static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) |
cf6eb489e perf probe: Show ... |
1420 1421 1422 |
{ struct available_var_finder *af = container_of(pf, struct available_var_finder, pf); |
6cca13bdf perf probe: Impro... |
1423 |
struct perf_probe_point *pp = &pf->pev->point; |
cf6eb489e perf probe: Show ... |
1424 |
struct variable_list *vl; |
f182e3e13 perf probe: Avoid... |
1425 1426 |
Dwarf_Die die_mem; int ret; |
cf6eb489e perf probe: Show ... |
1427 1428 1429 1430 1431 1432 1433 1434 |
/* Check number of tevs */ if (af->nvls == af->max_vls) { pr_warning("Too many( > %d) probe point found. ", af->max_vls); return -ERANGE; } vl = &af->vls[af->nvls++]; |
221d06118 perf probe: Fix t... |
1435 |
/* Trace point should be converted from subprogram DIE */ |
576b52372 perf probe: Fix p... |
1436 |
ret = convert_to_trace_point(&pf->sp_die, af->mod, pf->addr, |
6cca13bdf perf probe: Impro... |
1437 |
pp->retprobe, pp->function, &vl->point); |
cf6eb489e perf probe: Show ... |
1438 1439 1440 1441 1442 1443 1444 1445 |
if (ret < 0) return ret; pr_debug("Probe point found: %s+%lu ", vl->point.symbol, vl->point.offset); /* Find local variables */ |
4a77e2183 perf strlist: Mak... |
1446 |
vl->vars = strlist__new(NULL, NULL); |
cf6eb489e perf probe: Show ... |
1447 1448 |
if (vl->vars == NULL) return -ENOMEM; |
fb8c5a56c perf probe: Show ... |
1449 |
af->child = true; |
221d06118 perf probe: Fix t... |
1450 |
die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); |
cf6eb489e perf probe: Show ... |
1451 |
|
fb8c5a56c perf probe: Show ... |
1452 |
/* Find external variables */ |
ddb2f58f9 perf probe: Intro... |
1453 |
if (!probe_conf.show_ext_vars) |
fb8c5a56c perf probe: Show ... |
1454 |
goto out; |
ddb2f58f9 perf probe: Intro... |
1455 |
/* Don't need to search child DIE for external vars. */ |
fb8c5a56c perf probe: Show ... |
1456 |
af->child = false; |
f182e3e13 perf probe: Avoid... |
1457 |
die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); |
fb8c5a56c perf probe: Show ... |
1458 1459 |
out: |
cf6eb489e perf probe: Show ... |
1460 1461 1462 1463 1464 1465 1466 |
if (strlist__empty(vl->vars)) { strlist__delete(vl->vars); vl->vars = NULL; } return ret; } |
69e96eaa4 perf probe: Impro... |
1467 1468 1469 1470 1471 |
/* * Find available variables at given probe point * Return the number of found probe points. Return 0 if there is no * matched probe point. Return <0 if an error occurs. */ |
316c7136f perf tools: Finis... |
1472 |
int debuginfo__find_available_vars_at(struct debuginfo *dbg, |
ff7417835 perf probe: Intro... |
1473 |
struct perf_probe_event *pev, |
ddb2f58f9 perf probe: Intro... |
1474 |
struct variable_list **vls) |
cf6eb489e perf probe: Show ... |
1475 1476 1477 |
{ struct available_var_finder af = { .pf = {.pev = pev, .callback = add_available_vars}, |
316c7136f perf tools: Finis... |
1478 |
.mod = dbg->mod, |
ddb2f58f9 perf probe: Intro... |
1479 |
.max_vls = probe_conf.max_probes}; |
cf6eb489e perf probe: Show ... |
1480 1481 1482 |
int ret; /* Allocate result vls array */ |
ddb2f58f9 perf probe: Intro... |
1483 |
*vls = zalloc(sizeof(struct variable_list) * af.max_vls); |
cf6eb489e perf probe: Show ... |
1484 1485 1486 1487 1488 |
if (*vls == NULL) return -ENOMEM; af.vls = *vls; af.nvls = 0; |
316c7136f perf tools: Finis... |
1489 |
ret = debuginfo__find_probes(dbg, &af.pf); |
cf6eb489e perf probe: Show ... |
1490 1491 1492 |
if (ret < 0) { /* Free vlist for error */ while (af.nvls--) { |
74cf249d5 perf tools: Use z... |
1493 |
zfree(&af.vls[af.nvls].point.symbol); |
f5385650c perf tools: No ne... |
1494 |
strlist__delete(af.vls[af.nvls].vars); |
cf6eb489e perf probe: Show ... |
1495 |
} |
046625231 perf tools: Intro... |
1496 |
zfree(vls); |
cf6eb489e perf probe: Show ... |
1497 1498 1499 1500 |
return ret; } return (ret < 0) ? ret : af.nvls; |
4ea42b181 perf: Add perf pr... |
1501 |
} |
9b239a12b perf probe: Show ... |
1502 |
/* For the kernel module, we need a special code to get a DIE */ |
613f050d6 perf probe: Fix t... |
1503 1504 |
int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs, bool adjust_offset) |
9b239a12b perf probe: Show ... |
1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 |
{ int n, i; Elf32_Word shndx; Elf_Scn *scn; Elf *elf; GElf_Shdr mem, *shdr; const char *p; elf = dwfl_module_getelf(dbg->mod, &dbg->bias); if (!elf) return -EINVAL; /* Get the number of relocations */ n = dwfl_module_relocations(dbg->mod); if (n < 0) return -ENOENT; /* Search the relocation related .text section */ for (i = 0; i < n; i++) { p = dwfl_module_relocation_info(dbg->mod, i, &shndx); if (strcmp(p, ".text") == 0) { /* OK, get the section header */ scn = elf_getscn(elf, shndx); if (!scn) return -ENOENT; shdr = gelf_getshdr(scn, &mem); if (!shdr) return -ENOENT; *offs = shdr->sh_addr; |
613f050d6 perf probe: Fix t... |
1533 1534 |
if (adjust_offset) *offs -= shdr->sh_offset; |
9b239a12b perf probe: Show ... |
1535 1536 1537 1538 |
} } return 0; } |
fb1587d86 perf probe: List ... |
1539 |
/* Reverse search */ |
316c7136f perf tools: Finis... |
1540 |
int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, |
ff7417835 perf probe: Intro... |
1541 |
struct perf_probe_point *ppt) |
fb1587d86 perf probe: List ... |
1542 1543 |
{ Dwarf_Die cudie, spdie, indie; |
e08cfd4bd perf probe: Fix t... |
1544 1545 |
Dwarf_Addr _addr = 0, baseaddr = 0; const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; |
1d46ea2a6 perf probe: Fix l... |
1546 |
int baseline = 0, lineno = 0, ret = 0; |
fb1587d86 perf probe: List ... |
1547 |
|
d2d4edbeb perf probe: Fix t... |
1548 |
/* We always need to relocate the address for aranges */ |
613f050d6 perf probe: Fix t... |
1549 |
if (debuginfo__get_text_offset(dbg, &baseaddr, false) == 0) |
d2d4edbeb perf probe: Fix t... |
1550 |
addr += baseaddr; |
fb1587d86 perf probe: List ... |
1551 |
/* Find cu die */ |
0104fe69e perf probe: Remov... |
1552 |
if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) { |
0e43e5d22 perf probe: Clean... |
1553 1554 1555 |
pr_warning("Failed to find debug information for address %lx ", addr); |
75ec5a245 perf probe: Fix t... |
1556 1557 1558 |
ret = -EINVAL; goto end; } |
fb1587d86 perf probe: List ... |
1559 |
|
1d46ea2a6 perf probe: Fix l... |
1560 1561 1562 |
/* Find a corresponding line (filename and lineno) */ cu_find_lineinfo(&cudie, addr, &fname, &lineno); /* Don't care whether it failed or not */ |
fb1587d86 perf probe: List ... |
1563 |
|
1d46ea2a6 perf probe: Fix l... |
1564 |
/* Find a corresponding function (name, baseline and baseaddr) */ |
e0d153c69 perf-probe: Move ... |
1565 |
if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { |
1d46ea2a6 perf probe: Fix l... |
1566 |
/* Get function entry information */ |
e08cfd4bd perf probe: Fix t... |
1567 1568 |
func = basefunc = dwarf_diename(&spdie); if (!func || |
1d46ea2a6 perf probe: Fix l... |
1569 |
dwarf_entrypc(&spdie, &baseaddr) != 0 || |
e08cfd4bd perf probe: Fix t... |
1570 1571 |
dwarf_decl_line(&spdie, &baseline) != 0) { lineno = 0; |
1d46ea2a6 perf probe: Fix l... |
1572 |
goto post; |
e08cfd4bd perf probe: Fix t... |
1573 |
} |
1d46ea2a6 perf probe: Fix l... |
1574 |
|
1b286bdd5 perf probe: Fix t... |
1575 |
fname = dwarf_decl_file(&spdie); |
e08cfd4bd perf probe: Fix t... |
1576 |
if (addr == (unsigned long)baseaddr) { |
1d46ea2a6 perf probe: Fix l... |
1577 1578 |
/* Function entry - Relative line number is 0 */ lineno = baseline; |
e08cfd4bd perf probe: Fix t... |
1579 1580 1581 1582 1583 1584 1585 |
goto post; } /* Track down the inline functions step by step */ while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr, &indie)) { /* There is an inline function */ |
1d46ea2a6 perf probe: Fix l... |
1586 |
if (dwarf_entrypc(&indie, &_addr) == 0 && |
e08cfd4bd perf probe: Fix t... |
1587 |
_addr == addr) { |
1d46ea2a6 perf probe: Fix l... |
1588 1589 1590 |
/* * addr is at an inline function entry. * In this case, lineno should be the call-site |
e08cfd4bd perf probe: Fix t... |
1591 |
* line number. (overwrite lineinfo) |
1d46ea2a6 perf probe: Fix l... |
1592 1593 |
*/ lineno = die_get_call_lineno(&indie); |
e08cfd4bd perf probe: Fix t... |
1594 1595 1596 |
fname = die_get_call_file(&indie); break; } else { |
1d46ea2a6 perf probe: Fix l... |
1597 1598 1599 1600 1601 1602 |
/* * addr is in an inline function body. * Since lineno points one of the lines * of the inline function, baseline should * be the entry line of the inline function. */ |
b55a87ade perf probe: Remov... |
1603 |
tmp = dwarf_diename(&indie); |
e08cfd4bd perf probe: Fix t... |
1604 1605 1606 1607 1608 |
if (!tmp || dwarf_decl_line(&indie, &baseline) != 0) break; func = tmp; spdie = indie; |
b55a87ade perf probe: Remov... |
1609 |
} |
fb1587d86 perf probe: List ... |
1610 |
} |
e08cfd4bd perf probe: Fix t... |
1611 1612 1613 1614 |
/* Verify the lineno and baseline are in a same file */ tmp = dwarf_decl_file(&spdie); if (!tmp || strcmp(tmp, fname) != 0) lineno = 0; |
1d46ea2a6 perf probe: Fix l... |
1615 1616 1617 1618 1619 1620 |
} post: /* Make a relative line number or an offset */ if (lineno) ppt->line = lineno - baseline; |
e08cfd4bd perf probe: Fix t... |
1621 |
else if (basefunc) { |
1d46ea2a6 perf probe: Fix l... |
1622 |
ppt->offset = addr - (unsigned long)baseaddr; |
e08cfd4bd perf probe: Fix t... |
1623 1624 |
func = basefunc; } |
1d46ea2a6 perf probe: Fix l... |
1625 1626 1627 1628 |
/* Duplicate strings */ if (func) { ppt->function = strdup(func); |
02b95dadc perf probe: Remov... |
1629 1630 1631 1632 |
if (ppt->function == NULL) { ret = -ENOMEM; goto end; } |
fb1587d86 perf probe: List ... |
1633 |
} |
1d46ea2a6 perf probe: Fix l... |
1634 1635 1636 |
if (fname) { ppt->file = strdup(fname); if (ppt->file == NULL) { |
046625231 perf tools: Intro... |
1637 |
zfree(&ppt->function); |
1d46ea2a6 perf probe: Fix l... |
1638 1639 1640 1641 |
ret = -ENOMEM; goto end; } } |
fb1587d86 perf probe: List ... |
1642 |
end: |
1d46ea2a6 perf probe: Fix l... |
1643 1644 |
if (ret == 0 && (fname || func)) ret = 1; /* Found a point */ |
fb1587d86 perf probe: List ... |
1645 1646 |
return ret; } |
f6c903f58 perf probe: Show ... |
1647 1648 1649 1650 |
/* Add a line and store the src path */ static int line_range_add_line(const char *src, unsigned int lineno, struct line_range *lr) { |
7cf0b79e6 perf probe: Fix e... |
1651 |
/* Copy source path */ |
f6c903f58 perf probe: Show ... |
1652 |
if (!lr->path) { |
7cf0b79e6 perf probe: Fix e... |
1653 1654 1655 |
lr->path = strdup(src); if (lr->path == NULL) return -ENOMEM; |
f6c903f58 perf probe: Show ... |
1656 |
} |
5a62257a3 perf probe: Repla... |
1657 |
return intlist__add(lr->line_list, lineno); |
f6c903f58 perf probe: Show ... |
1658 |
} |
4cc9cec63 perf probe: Intro... |
1659 |
static int line_range_walk_cb(const char *fname, int lineno, |
1d037ca16 perf tools: Use _... |
1660 |
Dwarf_Addr addr __maybe_unused, |
4cc9cec63 perf probe: Intro... |
1661 |
void *data) |
f6c903f58 perf probe: Show ... |
1662 |
{ |
4cc9cec63 perf probe: Intro... |
1663 |
struct line_finder *lf = data; |
202c7c123 perf probe: Fix -... |
1664 |
int err; |
f6c903f58 perf probe: Show ... |
1665 |
|
4cc9cec63 perf probe: Intro... |
1666 |
if ((strtailcmp(fname, lf->fname) != 0) || |
f6c903f58 perf probe: Show ... |
1667 |
(lf->lno_s > lineno || lf->lno_e < lineno)) |
4cc9cec63 perf probe: Intro... |
1668 |
return 0; |
f6c903f58 perf probe: Show ... |
1669 |
|
202c7c123 perf probe: Fix -... |
1670 1671 1672 |
err = line_range_add_line(fname, lineno, lf->lr); if (err < 0 && err != -EEXIST) return err; |
f6c903f58 perf probe: Show ... |
1673 |
|
4cc9cec63 perf probe: Intro... |
1674 |
return 0; |
f6c903f58 perf probe: Show ... |
1675 |
} |
fb1587d86 perf probe: List ... |
1676 |
|
631c9def8 perf probe: Suppo... |
1677 |
/* Find line range from its line number */ |
b55a87ade perf probe: Remov... |
1678 |
static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) |
631c9def8 perf probe: Suppo... |
1679 |
{ |
4cc9cec63 perf probe: Intro... |
1680 |
int ret; |
f6c903f58 perf probe: Show ... |
1681 |
|
4cc9cec63 perf probe: Intro... |
1682 |
ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf); |
f6c903f58 perf probe: Show ... |
1683 |
|
804b36068 perf probe: Use e... |
1684 |
/* Update status */ |
f6c903f58 perf probe: Show ... |
1685 |
if (ret >= 0) |
5a62257a3 perf probe: Repla... |
1686 |
if (!intlist__empty(lf->lr->line_list)) |
f6c903f58 perf probe: Show ... |
1687 1688 1689 |
ret = lf->found = 1; else ret = 0; /* Lines are not found */ |
804b36068 perf probe: Use e... |
1690 |
else { |
046625231 perf tools: Intro... |
1691 |
zfree(&lf->lr->path); |
804b36068 perf probe: Use e... |
1692 |
} |
f6c903f58 perf probe: Show ... |
1693 |
return ret; |
631c9def8 perf probe: Suppo... |
1694 |
} |
161a26b0c perf probe: Check... |
1695 1696 |
static int line_range_inline_cb(Dwarf_Die *in_die, void *data) { |
182c228eb perf probe: Fix t... |
1697 |
int ret = find_line_range_by_line(in_die, data); |
36c0c588b perf probe: Fix t... |
1698 1699 1700 1701 |
/* * We have to check all instances of inlined function, because * some execution paths can be optimized out depends on the |
182c228eb perf probe: Fix t... |
1702 1703 |
* function argument of instances. However, if an error occurs, * it should be handled by the caller. |
36c0c588b perf probe: Fix t... |
1704 |
*/ |
182c228eb perf probe: Fix t... |
1705 |
return ret < 0 ? ret : 0; |
161a26b0c perf probe: Check... |
1706 |
} |
0dbb1cac1 perf probe: Fix f... |
1707 |
/* Search function definition from function name */ |
e92b85e1f perf probe: Use l... |
1708 |
static int line_range_search_cb(Dwarf_Die *sp_die, void *data) |
631c9def8 perf probe: Suppo... |
1709 |
{ |
b55a87ade perf probe: Remov... |
1710 1711 |
struct dwarf_callback_param *param = data; struct line_finder *lf = param->data; |
631c9def8 perf probe: Suppo... |
1712 |
struct line_range *lr = lf->lr; |
631c9def8 perf probe: Suppo... |
1713 |
|
7d21635ac perf probe: Fix t... |
1714 1715 1716 |
/* Check declared file */ if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) return DWARF_CB_OK; |
0dbb1cac1 perf probe: Fix f... |
1717 |
if (die_is_func_def(sp_die) && |
4c8593512 perf probe: Suppo... |
1718 |
die_match_name(sp_die, lr->function)) { |
e92b85e1f perf probe: Use l... |
1719 1720 |
lf->fname = dwarf_decl_file(sp_die); dwarf_decl_line(sp_die, &lr->offset); |
804b36068 perf probe: Use e... |
1721 1722 |
pr_debug("fname: %s, lineno:%d ", lf->fname, lr->offset); |
631c9def8 perf probe: Suppo... |
1723 |
lf->lno_s = lr->offset + lr->start; |
d3b63d7ae perf probe: Fix a... |
1724 1725 1726 1727 |
if (lf->lno_s < 0) /* Overflow */ lf->lno_s = INT_MAX; lf->lno_e = lr->offset + lr->end; if (lf->lno_e < 0) /* Overflow */ |
804b36068 perf probe: Use e... |
1728 |
lf->lno_e = INT_MAX; |
d3b63d7ae perf probe: Fix a... |
1729 1730 |
pr_debug("New line range: %d to %d ", lf->lno_s, lf->lno_e); |
631c9def8 perf probe: Suppo... |
1731 1732 |
lr->start = lf->lno_s; lr->end = lf->lno_e; |
e1ecbbc3f perf probe: Fix t... |
1733 |
if (!die_is_func_instance(sp_die)) |
db0d2c642 perf probe: Searc... |
1734 1735 1736 |
param->retval = die_walk_instances(sp_die, line_range_inline_cb, lf); else |
b55a87ade perf probe: Remov... |
1737 1738 |
param->retval = find_line_range_by_line(sp_die, lf); return DWARF_CB_ABORT; |
631c9def8 perf probe: Suppo... |
1739 |
} |
b55a87ade perf probe: Remov... |
1740 |
return DWARF_CB_OK; |
631c9def8 perf probe: Suppo... |
1741 |
} |
b55a87ade perf probe: Remov... |
1742 |
static int find_line_range_by_func(struct line_finder *lf) |
631c9def8 perf probe: Suppo... |
1743 |
{ |
b55a87ade perf probe: Remov... |
1744 1745 1746 |
struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); return param.retval; |
631c9def8 perf probe: Suppo... |
1747 |
} |
316c7136f perf tools: Finis... |
1748 |
int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr) |
631c9def8 perf probe: Suppo... |
1749 |
{ |
804b36068 perf probe: Use e... |
1750 |
struct line_finder lf = {.lr = lr, .found = 0}; |
b55a87ade perf probe: Remov... |
1751 |
int ret = 0; |
804b36068 perf probe: Use e... |
1752 1753 1754 |
Dwarf_Off off = 0, noff; size_t cuhl; Dwarf_Die *diep; |
6a330a3c8 perf probe: Suppo... |
1755 |
const char *comp_dir; |
804b36068 perf probe: Use e... |
1756 |
|
cd25f8bc2 perf probe: Add f... |
1757 1758 1759 1760 1761 1762 1763 |
/* Fastpath: lookup by function name from .debug_pubnames section */ if (lr->function) { struct pubname_callback_param pubname_param = { .function = lr->function, .file = lr->file, .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0}; struct dwarf_callback_param line_range_param = { .data = (void *)&lf, .retval = 0}; |
316c7136f perf tools: Finis... |
1764 |
dwarf_getpubnames(dbg->dbg, pubname_search_cb, |
ff7417835 perf probe: Intro... |
1765 |
&pubname_param, 0); |
cd25f8bc2 perf probe: Add f... |
1766 1767 1768 1769 1770 1771 |
if (pubname_param.found) { line_range_search_cb(&lf.sp_die, &line_range_param); if (lf.found) goto found; } } |
804b36068 perf probe: Use e... |
1772 |
/* Loop on CUs (Compilation Unit) */ |
b55a87ade perf probe: Remov... |
1773 |
while (!lf.found && ret >= 0) { |
316c7136f perf tools: Finis... |
1774 |
if (dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, |
ff7417835 perf probe: Intro... |
1775 |
NULL, NULL, NULL) != 0) |
631c9def8 perf probe: Suppo... |
1776 1777 1778 |
break; /* Get the DIE(Debugging Information Entry) of this CU */ |
316c7136f perf tools: Finis... |
1779 |
diep = dwarf_offdie(dbg->dbg, off + cuhl, &lf.cu_die); |
804b36068 perf probe: Use e... |
1780 1781 |
if (!diep) continue; |
631c9def8 perf probe: Suppo... |
1782 1783 1784 |
/* Check if target file is included. */ if (lr->file) |
2a9c8c360 perf probe: Add l... |
1785 |
lf.fname = cu_find_realpath(&lf.cu_die, lr->file); |
804b36068 perf probe: Use e... |
1786 |
else |
2a9c8c360 perf probe: Add l... |
1787 |
lf.fname = 0; |
631c9def8 perf probe: Suppo... |
1788 |
|
2a9c8c360 perf probe: Add l... |
1789 |
if (!lr->file || lf.fname) { |
631c9def8 perf probe: Suppo... |
1790 |
if (lr->function) |
b55a87ade perf probe: Remov... |
1791 |
ret = find_line_range_by_func(&lf); |
631c9def8 perf probe: Suppo... |
1792 1793 |
else { lf.lno_s = lr->start; |
d3b63d7ae perf probe: Fix a... |
1794 |
lf.lno_e = lr->end; |
b55a87ade perf probe: Remov... |
1795 |
ret = find_line_range_by_line(NULL, &lf); |
631c9def8 perf probe: Suppo... |
1796 |
} |
631c9def8 perf probe: Suppo... |
1797 |
} |
804b36068 perf probe: Use e... |
1798 |
off = noff; |
631c9def8 perf probe: Suppo... |
1799 |
} |
6a330a3c8 perf probe: Suppo... |
1800 |
|
cd25f8bc2 perf probe: Add f... |
1801 |
found: |
6a330a3c8 perf probe: Suppo... |
1802 1803 1804 1805 1806 1807 1808 1809 1810 |
/* Store comp_dir */ if (lf.found) { comp_dir = cu_get_comp_dir(&lf.cu_die); if (comp_dir) { lr->comp_dir = strdup(comp_dir); if (!lr->comp_dir) ret = -ENOMEM; } } |
7cf0b79e6 perf probe: Fix e... |
1811 1812 |
pr_debug("path: %s ", lr->path); |
b55a87ade perf probe: Remov... |
1813 |
return (ret < 0) ? ret : lf.found; |
631c9def8 perf probe: Suppo... |
1814 |
} |
09ed8975c perf probe: Find ... |
1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 |
/* * Find a src file from a DWARF tag path. Prepend optional source path prefix * and chop off leading directories that do not exist. Result is passed back as * a newly allocated path on success. * Return 0 if file was found and readable, -errno otherwise. */ int get_real_path(const char *raw_path, const char *comp_dir, char **new_path) { const char *prefix = symbol_conf.source_prefix; if (!prefix) { if (raw_path[0] != '/' && comp_dir) /* If not an absolute path, try to use comp_dir */ prefix = comp_dir; else { if (access(raw_path, R_OK) == 0) { *new_path = strdup(raw_path); return *new_path ? 0 : -ENOMEM; } else return -errno; } } *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2)); if (!*new_path) return -ENOMEM; for (;;) { sprintf(*new_path, "%s/%s", prefix, raw_path); if (access(*new_path, R_OK) == 0) return 0; if (!symbol_conf.source_prefix) { /* In case of searching comp_dir, don't retry */ zfree(new_path); return -errno; } switch (errno) { case ENAMETOOLONG: case ENOENT: case EROFS: case EFAULT: raw_path = strchr(++raw_path, '/'); if (!raw_path) { zfree(new_path); return -ENOENT; } continue; default: zfree(new_path); return -errno; } } } |