blob: 9ddd7dad2e6e736dbc03b946eb076d03e0626f2f [file] [log] [blame]
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001/*
2 * probe-finder.c : C expression to kprobe event converter
3 *
4 * Written by Masami Hiramatsu <mhiramat@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 */
21
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -030022#include <inttypes.h>
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -040023#include <sys/utsname.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <fcntl.h>
27#include <errno.h>
28#include <stdio.h>
29#include <unistd.h>
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -040030#include <stdlib.h>
31#include <string.h>
32#include <stdarg.h>
Ian Munsiecd932c52010-04-20 16:58:32 +100033#include <dwarf-regs.h>
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -040034
Masami Hiramatsu124bb832011-02-04 21:52:11 +090035#include <linux/bitops.h>
Masami Hiramatsu89c69c02009-10-16 20:08:10 -040036#include "event.h"
Masami Hiramatsua15ad2f2014-02-06 05:32:27 +000037#include "dso.h"
Masami Hiramatsu89c69c02009-10-16 20:08:10 -040038#include "debug.h"
Masami Hiramatsu5a622572014-02-06 05:32:09 +000039#include "intlist.h"
Masami Hiramatsu074fc0e2009-10-16 20:08:01 -040040#include "util.h"
Chase Douglas9ed7e1b2010-06-14 15:26:30 -040041#include "symbol.h"
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -040042#include "probe-finder.h"
Masami Hiramatsu180b2062016-08-18 17:58:31 +090043#include "probe-file.h"
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -040044
Masami Hiramatsu49849122010-04-12 13:17:15 -040045/* Kprobe tracer basic type is up to u64 */
46#define MAX_BASIC_TYPE_BITS 64
47
Masami Hiramatsu469b9b82010-10-21 19:13:41 +090048/* Dwarf FL wrappers */
Masami Hiramatsu469b9b82010-10-21 19:13:41 +090049static char *debuginfo_path; /* Currently dummy */
50
51static const Dwfl_Callbacks offline_callbacks = {
52 .find_debuginfo = dwfl_standard_find_debuginfo,
53 .debuginfo_path = &debuginfo_path,
54
55 .section_address = dwfl_offline_section_address,
56
57 /* We use this table for core files too. */
58 .find_elf = dwfl_build_id_find_elf,
59};
60
Masami Hiramatsu469b9b82010-10-21 19:13:41 +090061/* Get a Dwarf from offline image */
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -030062static int debuginfo__init_offline_dwarf(struct debuginfo *dbg,
Masami Hiramatsuff741782011-06-27 16:27:39 +090063 const char *path)
Masami Hiramatsu469b9b82010-10-21 19:13:41 +090064{
Masami Hiramatsuff741782011-06-27 16:27:39 +090065 int fd;
Masami Hiramatsu469b9b82010-10-21 19:13:41 +090066
Masami Hiramatsuff741782011-06-27 16:27:39 +090067 fd = open(path, O_RDONLY);
68 if (fd < 0)
69 return fd;
Masami Hiramatsu469b9b82010-10-21 19:13:41 +090070
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -030071 dbg->dwfl = dwfl_begin(&offline_callbacks);
72 if (!dbg->dwfl)
Masami Hiramatsuff741782011-06-27 16:27:39 +090073 goto error;
Masami Hiramatsu469b9b82010-10-21 19:13:41 +090074
Masami Hiramatsu91359492015-10-01 01:41:28 +090075 dwfl_report_begin(dbg->dwfl);
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -030076 dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd);
77 if (!dbg->mod)
Masami Hiramatsu469b9b82010-10-21 19:13:41 +090078 goto error;
79
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -030080 dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias);
81 if (!dbg->dbg)
Masami Hiramatsuff741782011-06-27 16:27:39 +090082 goto error;
83
Masami Hiramatsu91359492015-10-01 01:41:28 +090084 dwfl_report_end(dbg->dwfl, NULL, NULL);
85
Masami Hiramatsuff741782011-06-27 16:27:39 +090086 return 0;
Masami Hiramatsu469b9b82010-10-21 19:13:41 +090087error:
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -030088 if (dbg->dwfl)
89 dwfl_end(dbg->dwfl);
Masami Hiramatsuff741782011-06-27 16:27:39 +090090 else
91 close(fd);
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -030092 memset(dbg, 0, sizeof(*dbg));
Masami Hiramatsuff741782011-06-27 16:27:39 +090093
94 return -ENOENT;
Masami Hiramatsu469b9b82010-10-21 19:13:41 +090095}
96
Masami Hiramatsua15ad2f2014-02-06 05:32:27 +000097static struct debuginfo *__debuginfo__new(const char *path)
Masami Hiramatsuff741782011-06-27 16:27:39 +090098{
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -030099 struct debuginfo *dbg = zalloc(sizeof(*dbg));
100 if (!dbg)
Masami Hiramatsuff741782011-06-27 16:27:39 +0900101 return NULL;
102
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300103 if (debuginfo__init_offline_dwarf(dbg, path) < 0)
104 zfree(&dbg);
Masami Hiramatsua15ad2f2014-02-06 05:32:27 +0000105 if (dbg)
106 pr_debug("Open Debuginfo file: %s\n", path);
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -0300107 return dbg;
Masami Hiramatsuff741782011-06-27 16:27:39 +0900108}
109
Masami Hiramatsua15ad2f2014-02-06 05:32:27 +0000110enum dso_binary_type distro_dwarf_types[] = {
111 DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
112 DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
113 DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
114 DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
115 DSO_BINARY_TYPE__NOT_FOUND,
116};
117
118struct debuginfo *debuginfo__new(const char *path)
119{
120 enum dso_binary_type *type;
121 char buf[PATH_MAX], nil = '\0';
122 struct dso *dso;
123 struct debuginfo *dinfo = NULL;
124
125 /* Try to open distro debuginfo files */
126 dso = dso__new(path);
127 if (!dso)
128 goto out;
129
130 for (type = distro_dwarf_types;
131 !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND;
132 type++) {
133 if (dso__read_binary_type_filename(dso, *type, &nil,
134 buf, PATH_MAX) < 0)
135 continue;
136 dinfo = __debuginfo__new(buf);
137 }
Arnaldo Carvalho de Melod3a7c482015-06-02 11:53:26 -0300138 dso__put(dso);
Masami Hiramatsua15ad2f2014-02-06 05:32:27 +0000139
140out:
141 /* if failed to open all distro debuginfo, open given binary */
142 return dinfo ? : __debuginfo__new(path);
143}
144
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -0300145void debuginfo__delete(struct debuginfo *dbg)
Masami Hiramatsuff741782011-06-27 16:27:39 +0900146{
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -0300147 if (dbg) {
148 if (dbg->dwfl)
149 dwfl_end(dbg->dwfl);
150 free(dbg);
Masami Hiramatsuff741782011-06-27 16:27:39 +0900151 }
152}
153
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400154/*
155 * Probe finder related functions
156 */
157
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530158static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400159{
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530160 struct probe_trace_arg_ref *ref;
161 ref = zalloc(sizeof(struct probe_trace_arg_ref));
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400162 if (ref != NULL)
163 ref->offset = offs;
164 return ref;
165}
166
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900167/*
168 * Convert a location into trace_arg.
169 * If tvar == NULL, this just checks variable can be converted.
Masami Hiramatsu3d918a12013-10-11 16:10:26 +0900170 * If fentry == true and vr_die is a parameter, do huristic search
171 * for the location fuzzed by function entry mcount.
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900172 */
173static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
Masami Hiramatsu3d918a12013-10-11 16:10:26 +0900174 Dwarf_Op *fb_ops, Dwarf_Die *sp_die,
Masami Hiramatsu293d5b42016-08-26 01:24:57 +0900175 unsigned int machine,
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900176 struct probe_trace_arg *tvar)
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400177{
178 Dwarf_Attribute attr;
Masami Hiramatsu3d918a12013-10-11 16:10:26 +0900179 Dwarf_Addr tmp = 0;
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400180 Dwarf_Op *op;
181 size_t nops;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500182 unsigned int regn;
183 Dwarf_Word offs = 0;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400184 bool ref = false;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400185 const char *regs;
He Kuang349e8d22015-05-11 09:25:03 +0000186 int ret, ret2 = 0;
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400187
Masami Hiramatsu632941c2010-10-21 19:13:16 +0900188 if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)
189 goto static_var;
190
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400191 /* TODO: handle more than 1 exprs */
Masami Hiramatsu3d918a12013-10-11 16:10:26 +0900192 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
193 return -EINVAL; /* Broken DIE ? */
194 if (dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0) {
195 ret = dwarf_entrypc(sp_die, &tmp);
He Kuang349e8d22015-05-11 09:25:03 +0000196 if (ret)
197 return -ENOENT;
198
199 if (probe_conf.show_location_range &&
200 (dwarf_tag(vr_die) == DW_TAG_variable)) {
201 ret2 = -ERANGE;
202 } else if (addr != tmp ||
203 dwarf_tag(vr_die) != DW_TAG_formal_parameter) {
204 return -ENOENT;
205 }
206
207 ret = dwarf_highpc(sp_die, &tmp);
208 if (ret)
Masami Hiramatsu3d918a12013-10-11 16:10:26 +0900209 return -ENOENT;
210 /*
211 * This is fuzzed by fentry mcount. We try to find the
212 * parameter location at the earliest address.
213 */
214 for (addr += 1; addr <= tmp; addr++) {
215 if (dwarf_getlocation_addr(&attr, addr, &op,
216 &nops, 1) > 0)
217 goto found;
218 }
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400219 return -ENOENT;
220 }
Masami Hiramatsu3d918a12013-10-11 16:10:26 +0900221found:
222 if (nops == 0)
223 /* TODO: Support const_value */
224 return -ENOENT;
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400225
226 if (op->atom == DW_OP_addr) {
Masami Hiramatsu632941c2010-10-21 19:13:16 +0900227static_var:
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900228 if (!tvar)
He Kuang349e8d22015-05-11 09:25:03 +0000229 return ret2;
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400230 /* Static variables on memory (not stack), make @varname */
231 ret = strlen(dwarf_diename(vr_die));
232 tvar->value = zalloc(ret + 2);
233 if (tvar->value == NULL)
234 return -ENOMEM;
235 snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die));
236 tvar->ref = alloc_trace_arg_ref((long)offs);
237 if (tvar->ref == NULL)
238 return -ENOMEM;
He Kuang349e8d22015-05-11 09:25:03 +0000239 return ret2;
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400240 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400241
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400242 /* If this is based on frame buffer, set the offset */
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500243 if (op->atom == DW_OP_fbreg) {
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900244 if (fb_ops == NULL)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400245 return -ENOTSUP;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400246 ref = true;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500247 offs = op->number;
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900248 op = &fb_ops[0];
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500249 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400250
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500251 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
252 regn = op->atom - DW_OP_breg0;
253 offs += op->number;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400254 ref = true;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500255 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
256 regn = op->atom - DW_OP_reg0;
257 } else if (op->atom == DW_OP_bregx) {
258 regn = op->number;
259 offs += op->number2;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400260 ref = true;
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500261 } else if (op->atom == DW_OP_regx) {
262 regn = op->number;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400263 } else {
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900264 pr_debug("DW_OP %x is not supported.\n", op->atom);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400265 return -ENOTSUP;
266 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400267
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900268 if (!tvar)
He Kuang349e8d22015-05-11 09:25:03 +0000269 return ret2;
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900270
Masami Hiramatsu293d5b42016-08-26 01:24:57 +0900271 regs = get_dwarf_regstr(regn, machine);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400272 if (!regs) {
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900273 /* This should be a bug in DWARF or this tool */
Masami Hiramatsu0e43e5d2010-12-17 22:12:11 +0900274 pr_warning("Mapping for the register number %u "
275 "missing on this architecture.\n", regn);
He Kuang349e8d22015-05-11 09:25:03 +0000276 return -ENOTSUP;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400277 }
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400278
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400279 tvar->value = strdup(regs);
280 if (tvar->value == NULL)
281 return -ENOMEM;
282
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400283 if (ref) {
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400284 tvar->ref = alloc_trace_arg_ref((long)offs);
Masami Hiramatsue334016f12010-04-12 13:17:49 -0400285 if (tvar->ref == NULL)
286 return -ENOMEM;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400287 }
He Kuang349e8d22015-05-11 09:25:03 +0000288 return ret2;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400289}
290
Masami Hiramatsu124bb832011-02-04 21:52:11 +0900291#define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long))
292
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400293static int convert_variable_type(Dwarf_Die *vr_die,
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530294 struct probe_trace_arg *tvar,
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400295 const char *cast)
Masami Hiramatsu49849122010-04-12 13:17:15 -0400296{
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530297 struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
Masami Hiramatsu49849122010-04-12 13:17:15 -0400298 Dwarf_Die type;
299 char buf[16];
Masami Hiramatsu5f03cba2014-08-14 02:22:34 +0000300 char sbuf[STRERR_BUFSIZE];
Masami Hiramatsubcfc0822011-06-27 16:27:21 +0900301 int bsize, boffs, total;
Masami Hiramatsu49849122010-04-12 13:17:15 -0400302 int ret;
Masami Hiramatsu92543782016-08-18 17:58:47 +0900303 char prefix;
Masami Hiramatsu49849122010-04-12 13:17:15 -0400304
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400305 /* TODO: check all types */
Masami Hiramatsu92543782016-08-18 17:58:47 +0900306 if (cast && strcmp(cast, "string") != 0 && strcmp(cast, "x") != 0 &&
Naohiro Aota19f00b02016-08-09 11:40:08 +0900307 strcmp(cast, "s") != 0 && strcmp(cast, "u") != 0) {
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400308 /* Non string type is OK */
Masami Hiramatsu92543782016-08-18 17:58:47 +0900309 /* and respect signedness/hexadecimal cast */
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400310 tvar->type = strdup(cast);
311 return (tvar->type == NULL) ? -ENOMEM : 0;
312 }
313
Masami Hiramatsubcfc0822011-06-27 16:27:21 +0900314 bsize = dwarf_bitsize(vr_die);
315 if (bsize > 0) {
Masami Hiramatsu124bb832011-02-04 21:52:11 +0900316 /* This is a bitfield */
Masami Hiramatsubcfc0822011-06-27 16:27:21 +0900317 boffs = dwarf_bitoffset(vr_die);
318 total = dwarf_bytesize(vr_die);
319 if (boffs < 0 || total < 0)
320 return -ENOENT;
321 ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs,
322 BYTES_TO_BITS(total));
Masami Hiramatsu124bb832011-02-04 21:52:11 +0900323 goto formatted;
324 }
325
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400326 if (die_get_real_type(vr_die, &type) == NULL) {
327 pr_warning("Failed to get a type information of %s.\n",
328 dwarf_diename(vr_die));
329 return -ENOENT;
330 }
Masami Hiramatsu49849122010-04-12 13:17:15 -0400331
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400332 pr_debug("%s type is %s.\n",
333 dwarf_diename(vr_die), dwarf_diename(&type));
334
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400335 if (cast && strcmp(cast, "string") == 0) { /* String type */
336 ret = dwarf_tag(&type);
337 if (ret != DW_TAG_pointer_type &&
338 ret != DW_TAG_array_type) {
339 pr_warning("Failed to cast into string: "
Masami Hiramatsu0e43e5d2010-12-17 22:12:11 +0900340 "%s(%s) is not a pointer nor array.\n",
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400341 dwarf_diename(vr_die), dwarf_diename(&type));
342 return -EINVAL;
343 }
Hyeoncheol Lee7ce28b52012-09-11 16:57:28 +0900344 if (die_get_real_type(&type, &type) == NULL) {
345 pr_warning("Failed to get a type"
346 " information.\n");
347 return -ENOENT;
348 }
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400349 if (ret == DW_TAG_pointer_type) {
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400350 while (*ref_ptr)
351 ref_ptr = &(*ref_ptr)->next;
352 /* Add new reference with offset +0 */
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530353 *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref));
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400354 if (*ref_ptr == NULL) {
355 pr_warning("Out of memory error\n");
356 return -ENOMEM;
357 }
358 }
Masami Hiramatsu82175632010-07-09 18:29:17 +0900359 if (!die_compare_name(&type, "char") &&
360 !die_compare_name(&type, "unsigned char")) {
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400361 pr_warning("Failed to cast into string: "
Masami Hiramatsu0e43e5d2010-12-17 22:12:11 +0900362 "%s is not (unsigned) char *.\n",
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400363 dwarf_diename(vr_die));
364 return -EINVAL;
365 }
366 tvar->type = strdup(cast);
367 return (tvar->type == NULL) ? -ENOMEM : 0;
368 }
369
Naohiro Aota19f00b02016-08-09 11:40:08 +0900370 if (cast && (strcmp(cast, "u") == 0))
Masami Hiramatsu92543782016-08-18 17:58:47 +0900371 prefix = 'u';
Naohiro Aota19f00b02016-08-09 11:40:08 +0900372 else if (cast && (strcmp(cast, "s") == 0))
Masami Hiramatsu92543782016-08-18 17:58:47 +0900373 prefix = 's';
374 else if (cast && (strcmp(cast, "x") == 0) &&
375 probe_type_is_available(PROBE_TYPE_X))
376 prefix = 'x';
Naohiro Aota19f00b02016-08-09 11:40:08 +0900377 else
Masami Hiramatsu9880ce42016-08-18 17:59:07 +0900378 prefix = die_is_signed_type(&type) ? 's' :
379 probe_type_is_available(PROBE_TYPE_X) ? 'x' : 'u';
Naohiro Aota19f00b02016-08-09 11:40:08 +0900380
Masami Hiramatsubcfc0822011-06-27 16:27:21 +0900381 ret = dwarf_bytesize(&type);
382 if (ret <= 0)
Masami Hiramatsu124bb832011-02-04 21:52:11 +0900383 /* No size ... try to use default type */
384 return 0;
Masami Hiramatsubcfc0822011-06-27 16:27:21 +0900385 ret = BYTES_TO_BITS(ret);
Masami Hiramatsu49849122010-04-12 13:17:15 -0400386
Masami Hiramatsu124bb832011-02-04 21:52:11 +0900387 /* Check the bitwidth */
388 if (ret > MAX_BASIC_TYPE_BITS) {
389 pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n",
390 dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
391 ret = MAX_BASIC_TYPE_BITS;
Masami Hiramatsu49849122010-04-12 13:17:15 -0400392 }
Masami Hiramatsu92543782016-08-18 17:58:47 +0900393 ret = snprintf(buf, 16, "%c%d", prefix, ret);
Masami Hiramatsu124bb832011-02-04 21:52:11 +0900394
395formatted:
396 if (ret < 0 || ret >= 16) {
397 if (ret >= 16)
398 ret = -E2BIG;
399 pr_warning("Failed to convert variable type: %s\n",
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -0300400 str_error_r(-ret, sbuf, sizeof(sbuf)));
Masami Hiramatsu124bb832011-02-04 21:52:11 +0900401 return ret;
402 }
403 tvar->type = strdup(buf);
404 if (tvar->type == NULL)
405 return -ENOMEM;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400406 return 0;
Masami Hiramatsu49849122010-04-12 13:17:15 -0400407}
408
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400409static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400410 struct perf_probe_arg_field *field,
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530411 struct probe_trace_arg_ref **ref_ptr,
Masami Hiramatsu49849122010-04-12 13:17:15 -0400412 Dwarf_Die *die_mem)
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400413{
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530414 struct probe_trace_arg_ref *ref = *ref_ptr;
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400415 Dwarf_Die type;
416 Dwarf_Word offs;
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400417 int ret, tag;
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400418
419 pr_debug("converting %s in %s\n", field->name, varname);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400420 if (die_get_real_type(vr_die, &type) == NULL) {
421 pr_warning("Failed to get the type of %s.\n", varname);
422 return -ENOENT;
423 }
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400424 pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type));
425 tag = dwarf_tag(&type);
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400426
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400427 if (field->name[0] == '[' &&
428 (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) {
429 if (field->next)
430 /* Save original type for next field */
431 memcpy(die_mem, &type, sizeof(*die_mem));
432 /* Get the type of this array */
433 if (die_get_real_type(&type, &type) == NULL) {
434 pr_warning("Failed to get the type of %s.\n", varname);
435 return -ENOENT;
436 }
437 pr_debug2("Array real type: (%x)\n",
438 (unsigned)dwarf_dieoffset(&type));
439 if (tag == DW_TAG_pointer_type) {
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530440 ref = zalloc(sizeof(struct probe_trace_arg_ref));
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400441 if (ref == NULL)
442 return -ENOMEM;
443 if (*ref_ptr)
444 (*ref_ptr)->next = ref;
445 else
446 *ref_ptr = ref;
447 }
Masami Hiramatsubcfc0822011-06-27 16:27:21 +0900448 ref->offset += dwarf_bytesize(&type) * field->index;
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400449 if (!field->next)
450 /* Save vr_die for converting types */
451 memcpy(die_mem, vr_die, sizeof(*die_mem));
452 goto next;
453 } else if (tag == DW_TAG_pointer_type) {
454 /* Check the pointer and dereference */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400455 if (!field->ref) {
456 pr_err("Semantic error: %s must be referred by '->'\n",
457 field->name);
458 return -EINVAL;
459 }
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400460 /* Get the type pointed by this pointer */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400461 if (die_get_real_type(&type, &type) == NULL) {
462 pr_warning("Failed to get the type of %s.\n", varname);
463 return -ENOENT;
464 }
Masami Hiramatsu12e5a7a2010-04-02 12:50:53 -0400465 /* Verify it is a data structure */
Hyeoncheol Lee7b0295b2012-09-12 16:57:45 +0900466 tag = dwarf_tag(&type);
467 if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
Masahiro Yamada03440c42017-02-27 14:28:49 -0800468 pr_warning("%s is not a data structure nor a union.\n",
Hyeoncheol Lee7b0295b2012-09-12 16:57:45 +0900469 varname);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400470 return -EINVAL;
471 }
Masami Hiramatsu12e5a7a2010-04-02 12:50:53 -0400472
Srikar Dronamraju0e608362010-07-29 19:43:51 +0530473 ref = zalloc(sizeof(struct probe_trace_arg_ref));
Masami Hiramatsue334016f12010-04-12 13:17:49 -0400474 if (ref == NULL)
475 return -ENOMEM;
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400476 if (*ref_ptr)
477 (*ref_ptr)->next = ref;
478 else
479 *ref_ptr = ref;
480 } else {
Masami Hiramatsu12e5a7a2010-04-02 12:50:53 -0400481 /* Verify it is a data structure */
Hyeoncheol Lee7b0295b2012-09-12 16:57:45 +0900482 if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
Masahiro Yamada03440c42017-02-27 14:28:49 -0800483 pr_warning("%s is not a data structure nor a union.\n",
Hyeoncheol Lee7b0295b2012-09-12 16:57:45 +0900484 varname);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400485 return -EINVAL;
486 }
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400487 if (field->name[0] == '[') {
Masanari Iidad939be32015-02-27 23:52:31 +0900488 pr_err("Semantic error: %s is not a pointer"
Masami Hiramatsu0e43e5d2010-12-17 22:12:11 +0900489 " nor array.\n", varname);
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400490 return -EINVAL;
491 }
Masami Hiramatsuc7273832015-04-02 16:33:12 +0900492 /* While prcessing unnamed field, we don't care about this */
493 if (field->ref && dwarf_diename(vr_die)) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400494 pr_err("Semantic error: %s must be referred by '.'\n",
495 field->name);
496 return -EINVAL;
497 }
498 if (!ref) {
499 pr_warning("Structure on a register is not "
500 "supported yet.\n");
501 return -ENOTSUP;
502 }
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400503 }
504
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400505 if (die_find_member(&type, field->name, die_mem) == NULL) {
Arnaldo Carvalho de Melo9ef04382013-10-24 17:36:31 -0300506 pr_warning("%s(type:%s) has no member %s.\n", varname,
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400507 dwarf_diename(&type), field->name);
508 return -EINVAL;
509 }
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400510
511 /* Get the offset of the field */
Hyeoncheol Lee7b0295b2012-09-12 16:57:45 +0900512 if (tag == DW_TAG_union_type) {
513 offs = 0;
514 } else {
515 ret = die_get_data_member_location(die_mem, &offs);
516 if (ret < 0) {
517 pr_warning("Failed to get the offset of %s.\n",
518 field->name);
519 return ret;
520 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400521 }
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400522 ref->offset += (long)offs;
523
Masami Hiramatsuc7273832015-04-02 16:33:12 +0900524 /* If this member is unnamed, we need to reuse this field */
525 if (!dwarf_diename(die_mem))
526 return convert_variable_fields(die_mem, varname, field,
527 &ref, die_mem);
528
Masami Hiramatsub2a3c122010-05-19 15:57:42 -0400529next:
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400530 /* Converting next field */
531 if (field->next)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400532 return convert_variable_fields(die_mem, field->name,
Masami Hiramatsude1439d2010-04-14 17:44:00 -0300533 field->next, &ref, die_mem);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400534 else
535 return 0;
Masami Hiramatsu7df2f322010-03-16 18:06:26 -0400536}
537
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400538/* Show a variables in kprobe event format */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400539static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400540{
Masami Hiramatsu49849122010-04-12 13:17:15 -0400541 Dwarf_Die die_mem;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400542 int ret;
543
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400544 pr_debug("Converting variable %s into trace event.\n",
545 dwarf_diename(vr_die));
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500546
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900547 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
Masami Hiramatsu293d5b42016-08-26 01:24:57 +0900548 &pf->sp_die, pf->machine, pf->tvar);
He Kuang7d5eaba2015-05-11 09:25:04 +0000549 if (ret == -ENOENT || ret == -EINVAL) {
550 pr_err("Failed to find the location of the '%s' variable at this address.\n"
551 " Perhaps it has been optimized out.\n"
552 " Use -V with the --range option to show '%s' location range.\n",
553 pf->pvar->var, pf->pvar->var);
554 } else if (ret == -ENOTSUP)
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900555 pr_err("Sorry, we don't support this variable location yet.\n");
Masami Hiramatsu0c188a02014-05-29 19:52:32 +0900556 else if (ret == 0 && pf->pvar->field) {
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400557 ret = convert_variable_fields(vr_die, pf->pvar->var,
558 pf->pvar->field, &pf->tvar->ref,
559 &die_mem);
Masami Hiramatsu49849122010-04-12 13:17:15 -0400560 vr_die = &die_mem;
561 }
Masami Hiramatsu73317b92010-05-19 15:57:35 -0400562 if (ret == 0)
563 ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type);
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500564 /* *expr will be cached in libdw. Don't free it. */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400565 return ret;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400566}
567
Masami Hiramatsu221d0612011-08-11 20:02:59 +0900568/* Find a variable in a scope DIE */
569static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400570{
Masami Hiramatsuf182e3e2011-08-11 20:03:05 +0900571 Dwarf_Die vr_die;
Masami Hiramatsu909b0362016-04-28 03:37:14 +0900572 char *buf, *ptr;
Masami Hiramatsuf182e3e2011-08-11 20:03:05 +0900573 int ret = 0;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400574
Wang Nanda15bd92015-08-26 10:57:45 +0000575 /* Copy raw parameters */
576 if (!is_c_varname(pf->pvar->var))
577 return copy_to_probe_trace_arg(pf->tvar, pf->pvar);
Masami Hiramatsu367e94c2010-08-27 20:38:59 +0900578
Masami Hiramatsu48481932010-04-12 13:16:53 -0400579 if (pf->pvar->name)
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400580 pf->tvar->name = strdup(pf->pvar->name);
Masami Hiramatsu48481932010-04-12 13:16:53 -0400581 else {
Masami Hiramatsu909b0362016-04-28 03:37:14 +0900582 buf = synthesize_perf_probe_arg(pf->pvar);
583 if (!buf)
584 return -ENOMEM;
Masami Hiramatsu11a1ca32010-04-12 13:17:22 -0400585 ptr = strchr(buf, ':'); /* Change type separator to _ */
586 if (ptr)
587 *ptr = '_';
Masami Hiramatsu909b0362016-04-28 03:37:14 +0900588 pf->tvar->name = buf;
Masami Hiramatsu48481932010-04-12 13:16:53 -0400589 }
Masami Hiramatsu02b95da2010-04-12 13:17:56 -0400590 if (pf->tvar->name == NULL)
591 return -ENOMEM;
Masami Hiramatsu48481932010-04-12 13:16:53 -0400592
Masami Hiramatsuf182e3e2011-08-11 20:03:05 +0900593 pr_debug("Searching '%s' variable in context.\n", pf->pvar->var);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400594 /* Search child die for local variables and parameters. */
Masami Hiramatsuf182e3e2011-08-11 20:03:05 +0900595 if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) {
596 /* Search again in global variables */
He Kuangd13855e2015-04-25 16:08:58 +0800597 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var,
598 0, &vr_die)) {
Masami Hiramatsu36d789a2014-06-06 07:13:45 +0000599 pr_warning("Failed to find '%s' in this function.\n",
600 pf->pvar->var);
Masami Hiramatsuf182e3e2011-08-11 20:03:05 +0900601 ret = -ENOENT;
He Kuangd13855e2015-04-25 16:08:58 +0800602 }
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400603 }
Masami Hiramatsuf66fedc2011-08-20 14:39:23 +0900604 if (ret >= 0)
Masami Hiramatsuf182e3e2011-08-11 20:03:05 +0900605 ret = convert_variable(&vr_die, pf);
606
Masami Hiramatsub7dcb852010-05-19 15:57:49 -0400607 return ret;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400608}
609
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900610/* Convert subprogram DIE to trace point */
Masami Hiramatsu576b5232013-09-25 22:16:16 +0900611static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
612 Dwarf_Addr paddr, bool retprobe,
Masami Hiramatsu6cca13b2015-10-01 01:41:37 +0900613 const char *function,
Masami Hiramatsu576b5232013-09-25 22:16:16 +0900614 struct probe_trace_point *tp)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400615{
Prashanth Nageshappa26b79522012-02-24 13:11:39 +0530616 Dwarf_Addr eaddr, highaddr;
Masami Hiramatsu576b5232013-09-25 22:16:16 +0900617 GElf_Sym sym;
618 const char *symbol;
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500619
Masami Hiramatsu576b5232013-09-25 22:16:16 +0900620 /* Verify the address is correct */
621 if (dwarf_entrypc(sp_die, &eaddr) != 0) {
622 pr_warning("Failed to get entry address of %s\n",
623 dwarf_diename(sp_die));
624 return -ENOENT;
625 }
626 if (dwarf_highpc(sp_die, &highaddr) != 0) {
627 pr_warning("Failed to get end address of %s\n",
628 dwarf_diename(sp_die));
629 return -ENOENT;
630 }
631 if (paddr > highaddr) {
632 pr_warning("Offset specified is greater than size of %s\n",
633 dwarf_diename(sp_die));
634 return -EINVAL;
635 }
636
Masami Hiramatsu664fee32014-09-17 08:41:01 +0000637 symbol = dwarf_diename(sp_die);
Masami Hiramatsu576b5232013-09-25 22:16:16 +0900638 if (!symbol) {
Masami Hiramatsu664fee32014-09-17 08:41:01 +0000639 /* Try to get the symbol name from symtab */
640 symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
641 if (!symbol) {
642 pr_warning("Failed to find symbol at 0x%lx\n",
643 (unsigned long)paddr);
644 return -ENOENT;
645 }
646 eaddr = sym.st_value;
Masami Hiramatsu576b5232013-09-25 22:16:16 +0900647 }
Masami Hiramatsu664fee32014-09-17 08:41:01 +0000648 tp->offset = (unsigned long)(paddr - eaddr);
Masami Hiramatsufb7345b2013-12-26 05:41:53 +0000649 tp->address = (unsigned long)paddr;
Masami Hiramatsu576b5232013-09-25 22:16:16 +0900650 tp->symbol = strdup(symbol);
651 if (!tp->symbol)
652 return -ENOMEM;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400653
Masami Hiramatsu04ddd042010-08-27 20:38:53 +0900654 /* Return probe must be on the head of a subprogram */
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900655 if (retprobe) {
656 if (eaddr != paddr) {
Masami Hiramatsu6cca13b2015-10-01 01:41:37 +0900657 pr_warning("Failed to find \"%s%%return\",\n"
658 " because %s is an inlined function and"
659 " has no return point.\n", function,
660 function);
Masami Hiramatsu04ddd042010-08-27 20:38:53 +0900661 return -EINVAL;
662 }
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900663 tp->retprobe = true;
Masami Hiramatsu04ddd042010-08-27 20:38:53 +0900664 }
665
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900666 return 0;
667}
668
Masami Hiramatsu221d0612011-08-11 20:02:59 +0900669/* Call probe_finder callback with scope DIE */
670static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900671{
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900672 Dwarf_Attribute fb_attr;
Masami Hiramatsu4d3b1622015-11-25 19:34:32 +0900673 Dwarf_Frame *frame = NULL;
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900674 size_t nops;
675 int ret;
676
Masami Hiramatsu221d0612011-08-11 20:02:59 +0900677 if (!sc_die) {
678 pr_err("Caller must pass a scope DIE. Program error.\n");
679 return -EINVAL;
680 }
681
682 /* If not a real subprogram, find a real one */
Masami Hiramatsu0dbb1ca2012-04-23 12:24:36 +0900683 if (!die_is_func_def(sc_die)) {
Masami Hiramatsu221d0612011-08-11 20:02:59 +0900684 if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) {
Naveen N. Raod4c537e2015-04-30 17:12:31 +0530685 if (die_find_tailfunc(&pf->cu_die, pf->addr, &pf->sp_die)) {
686 pr_warning("Ignoring tail call from %s\n",
687 dwarf_diename(&pf->sp_die));
688 return 0;
689 } else {
690 pr_warning("Failed to find probe point in any "
691 "functions.\n");
692 return -ENOENT;
693 }
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900694 }
Masami Hiramatsu221d0612011-08-11 20:02:59 +0900695 } else
696 memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die));
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400697
Masami Hiramatsu221d0612011-08-11 20:02:59 +0900698 /* Get the frame base attribute/ops from subprogram */
699 dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr);
Masami Hiramatsud0cb4262010-03-15 13:02:35 -0400700 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
Masami Hiramatsua34a9852010-04-12 13:17:29 -0400701 if (ret <= 0 || nops == 0) {
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500702 pf->fb_ops = NULL;
Masami Hiramatsu7752f1b2010-05-10 13:12:07 -0400703#if _ELFUTILS_PREREQ(0, 142)
Masami Hiramatsua34a9852010-04-12 13:17:29 -0400704 } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
Hemant Kumar270bde12016-02-02 20:56:46 +0530705 (pf->cfi_eh != NULL || pf->cfi_dbg != NULL)) {
706 if ((dwarf_cfi_addrframe(pf->cfi_eh, pf->addr, &frame) != 0 &&
707 (dwarf_cfi_addrframe(pf->cfi_dbg, pf->addr, &frame) != 0)) ||
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400708 dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
Masami Hiramatsu0e43e5d2010-12-17 22:12:11 +0900709 pr_warning("Failed to get call frame on 0x%jx\n",
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400710 (uintmax_t)pf->addr);
Masami Hiramatsu4d3b1622015-11-25 19:34:32 +0900711 free(frame);
712 return -ENOENT;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400713 }
Masami Hiramatsu7752f1b2010-05-10 13:12:07 -0400714#endif
Masami Hiramatsua34a9852010-04-12 13:17:29 -0400715 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500716
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900717 /* Call finder's callback handler */
Masami Hiramatsu4d3b1622015-11-25 19:34:32 +0900718 ret = pf->callback(sc_die, pf);
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500719
Masami Hiramatsu4d3b1622015-11-25 19:34:32 +0900720 /* Since *pf->fb_ops can be a part of frame. we should free it here. */
721 free(frame);
Masami Hiramatsu804b3602010-02-25 08:35:42 -0500722 pf->fb_ops = NULL;
Masami Hiramatsucf6eb482010-10-21 19:13:23 +0900723
724 return ret;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400725}
726
Masami Hiramatsu221d0612011-08-11 20:02:59 +0900727struct find_scope_param {
728 const char *function;
729 const char *file;
730 int line;
731 int diff;
732 Dwarf_Die *die_mem;
733 bool found;
734};
735
736static int find_best_scope_cb(Dwarf_Die *fn_die, void *data)
737{
738 struct find_scope_param *fsp = data;
739 const char *file;
740 int lno;
741
742 /* Skip if declared file name does not match */
743 if (fsp->file) {
744 file = dwarf_decl_file(fn_die);
745 if (!file || strcmp(fsp->file, file) != 0)
746 return 0;
747 }
748 /* If the function name is given, that's what user expects */
749 if (fsp->function) {
Masami Hiramatsu4c859352015-05-08 10:03:35 +0900750 if (die_match_name(fn_die, fsp->function)) {
Masami Hiramatsu221d0612011-08-11 20:02:59 +0900751 memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
752 fsp->found = true;
753 return 1;
754 }
755 } else {
756 /* With the line number, find the nearest declared DIE */
757 dwarf_decl_line(fn_die, &lno);
758 if (lno < fsp->line && fsp->diff > fsp->line - lno) {
759 /* Keep a candidate and continue */
760 fsp->diff = fsp->line - lno;
761 memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
762 fsp->found = true;
763 }
764 }
765 return 0;
766}
767
768/* Find an appropriate scope fits to given conditions */
769static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem)
770{
771 struct find_scope_param fsp = {
772 .function = pf->pev->point.function,
773 .file = pf->fname,
774 .line = pf->lno,
775 .diff = INT_MAX,
776 .die_mem = die_mem,
777 .found = false,
778 };
779
780 cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp);
781
782 return fsp.found ? die_mem : NULL;
783}
784
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +0900785static int probe_point_line_walker(const char *fname, int lineno,
786 Dwarf_Addr addr, void *data)
787{
788 struct probe_finder *pf = data;
Masami Hiramatsu221d0612011-08-11 20:02:59 +0900789 Dwarf_Die *sc_die, die_mem;
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +0900790 int ret;
791
792 if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
793 return 0;
794
795 pf->addr = addr;
Masami Hiramatsu221d0612011-08-11 20:02:59 +0900796 sc_die = find_best_scope(pf, &die_mem);
797 if (!sc_die) {
798 pr_warning("Failed to find scope of probe point.\n");
799 return -ENOENT;
800 }
801
802 ret = call_probe_finder(sc_die, pf);
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +0900803
804 /* Continue if no error, because the line will be in inline function */
Arnaldo Carvalho de Melofbee6322011-02-21 13:23:57 -0300805 return ret < 0 ? ret : 0;
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +0900806}
807
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400808/* Find probe point from its line number */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400809static int find_probe_point_by_line(struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400810{
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +0900811 return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf);
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400812}
813
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500814/* Find lines which match lazy pattern */
Masami Hiramatsu5a622572014-02-06 05:32:09 +0000815static int find_lazy_match_lines(struct intlist *list,
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500816 const char *fname, const char *pat)
817{
Franck Bui-Huuf50c2162011-01-13 11:18:30 +0100818 FILE *fp;
819 char *line = NULL;
820 size_t line_len;
821 ssize_t len;
822 int count = 0, linenum = 1;
Masami Hiramatsu5f03cba2014-08-14 02:22:34 +0000823 char sbuf[STRERR_BUFSIZE];
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500824
Franck Bui-Huuf50c2162011-01-13 11:18:30 +0100825 fp = fopen(fname, "r");
826 if (!fp) {
Masami Hiramatsu5f03cba2014-08-14 02:22:34 +0000827 pr_warning("Failed to open %s: %s\n", fname,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -0300828 str_error_r(errno, sbuf, sizeof(sbuf)));
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300829 return -errno;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400830 }
831
Franck Bui-Huuf50c2162011-01-13 11:18:30 +0100832 while ((len = getline(&line, &line_len, fp)) > 0) {
833
834 if (line[len - 1] == '\n')
835 line[len - 1] = '\0';
836
837 if (strlazymatch(line, pat)) {
Masami Hiramatsu5a622572014-02-06 05:32:09 +0000838 intlist__add(list, linenum);
Franck Bui-Huuf50c2162011-01-13 11:18:30 +0100839 count++;
840 }
841 linenum++;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400842 }
Arnaldo Carvalho de Melob448c4b2010-05-18 23:04:28 -0300843
Franck Bui-Huuf50c2162011-01-13 11:18:30 +0100844 if (ferror(fp))
845 count = -errno;
846 free(line);
847 fclose(fp);
848
849 if (count == 0)
850 pr_debug("No matched lines found in %s.\n", fname);
851 return count;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500852}
853
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +0900854static int probe_point_lazy_walker(const char *fname, int lineno,
855 Dwarf_Addr addr, void *data)
856{
857 struct probe_finder *pf = data;
Masami Hiramatsu221d0612011-08-11 20:02:59 +0900858 Dwarf_Die *sc_die, die_mem;
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +0900859 int ret;
860
Masami Hiramatsu5a622572014-02-06 05:32:09 +0000861 if (!intlist__has_entry(pf->lcache, lineno) ||
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +0900862 strtailcmp(fname, pf->fname) != 0)
863 return 0;
864
865 pr_debug("Probe line found: line:%d addr:0x%llx\n",
866 lineno, (unsigned long long)addr);
867 pf->addr = addr;
Masami Hiramatsu221d0612011-08-11 20:02:59 +0900868 pf->lno = lineno;
869 sc_die = find_best_scope(pf, &die_mem);
870 if (!sc_die) {
871 pr_warning("Failed to find scope of probe point.\n");
872 return -ENOENT;
873 }
874
875 ret = call_probe_finder(sc_die, pf);
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +0900876
877 /*
878 * Continue if no error, because the lazy pattern will match
879 * to other lines
880 */
Ingo Molnar5e814dd2011-03-15 20:51:09 +0100881 return ret < 0 ? ret : 0;
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +0900882}
883
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500884/* Find probe points from lazy pattern */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400885static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500886{
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400887 int ret = 0;
Naohiro Aota09ed8972015-03-13 14:18:40 +0900888 char *fpath;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500889
Masami Hiramatsu5a622572014-02-06 05:32:09 +0000890 if (intlist__empty(pf->lcache)) {
Naohiro Aota09ed8972015-03-13 14:18:40 +0900891 const char *comp_dir;
892
893 comp_dir = cu_get_comp_dir(&pf->cu_die);
894 ret = get_real_path(pf->fname, comp_dir, &fpath);
895 if (ret < 0) {
896 pr_warning("Failed to find source file path.\n");
897 return ret;
898 }
899
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500900 /* Matching lazy line pattern */
Naohiro Aota09ed8972015-03-13 14:18:40 +0900901 ret = find_lazy_match_lines(pf->lcache, fpath,
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400902 pf->pev->point.lazy_line);
Naohiro Aota09ed8972015-03-13 14:18:40 +0900903 free(fpath);
Franck Bui-Huuf50c2162011-01-13 11:18:30 +0100904 if (ret <= 0)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400905 return ret;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500906 }
907
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +0900908 return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500909}
910
Ravi Bangoriae47392b2016-08-03 14:28:45 +0530911static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf)
912{
913 struct perf_probe_point *pp = &pf->pev->point;
914
915 /* Not uprobe? */
916 if (!pf->pev->uprobes)
917 return;
918
919 /* Compiled with optimization? */
Ravi Bangoria6243b9d2016-08-30 14:09:37 +0530920 if (die_is_optimized_target(&pf->cu_die))
Ravi Bangoriae47392b2016-08-03 14:28:45 +0530921 return;
922
923 /* Don't know entrypc? */
924 if (!pf->addr)
925 return;
926
927 /* Only FUNC and FUNC@SRC are eligible. */
928 if (!pp->function || pp->line || pp->retprobe || pp->lazy_line ||
929 pp->offset || pp->abs_address)
930 return;
931
932 /* Not interested in func parameter? */
933 if (!perf_probe_with_var(pf->pev))
934 return;
935
936 pr_info("Target program is compiled without optimization. Skipping prologue.\n"
937 "Probe on address 0x%" PRIx64 " to force probing at the function entry.\n\n",
938 pf->addr);
939
Ravi Bangoria6243b9d2016-08-30 14:09:37 +0530940 die_skip_prologue(sp_die, &pf->cu_die, &pf->addr);
Ravi Bangoriae47392b2016-08-03 14:28:45 +0530941}
942
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500943static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400944{
Masami Hiramatsudb0d2c62011-08-11 20:03:11 +0900945 struct probe_finder *pf = data;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400946 struct perf_probe_point *pp = &pf->pev->point;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400947 Dwarf_Addr addr;
Masami Hiramatsudb0d2c62011-08-11 20:03:11 +0900948 int ret;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -0400949
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500950 if (pp->lazy_line)
Masami Hiramatsudb0d2c62011-08-11 20:03:11 +0900951 ret = find_probe_point_lazy(in_die, pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500952 else {
953 /* Get probe address */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400954 if (dwarf_entrypc(in_die, &addr) != 0) {
Masami Hiramatsu0e43e5d2010-12-17 22:12:11 +0900955 pr_warning("Failed to get entry address of %s.\n",
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400956 dwarf_diename(in_die));
Masami Hiramatsudb0d2c62011-08-11 20:03:11 +0900957 return -ENOENT;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400958 }
Masami Hiramatsu0ad45b32016-09-24 00:35:07 +0900959 if (addr == 0) {
960 pr_debug("%s has no valid entry address. skipped.\n",
961 dwarf_diename(in_die));
962 return -ENOENT;
963 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400964 pf->addr = addr;
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500965 pf->addr += pp->offset;
966 pr_debug("found inline addr: 0x%jx\n",
967 (uintmax_t)pf->addr);
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500968
Masami Hiramatsudb0d2c62011-08-11 20:03:11 +0900969 ret = call_probe_finder(in_die, pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500970 }
971
Masami Hiramatsudb0d2c62011-08-11 20:03:11 +0900972 return ret;
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500973}
974
Masami Hiramatsudb0d2c62011-08-11 20:03:11 +0900975/* Callback parameter with return value for libdw */
976struct dwarf_callback_param {
977 void *data;
978 int retval;
979};
980
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500981/* Search function from function name */
982static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
983{
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400984 struct dwarf_callback_param *param = data;
985 struct probe_finder *pf = param->data;
Masami Hiramatsu4235b042010-03-16 18:06:12 -0400986 struct perf_probe_point *pp = &pf->pev->point;
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500987
988 /* Check tag and diename */
Masami Hiramatsu0dbb1ca2012-04-23 12:24:36 +0900989 if (!die_is_func_def(sp_die) ||
Masami Hiramatsu4c859352015-05-08 10:03:35 +0900990 !die_match_name(sp_die, pp->function))
Masami Hiramatsub55a87a2010-04-12 13:17:35 -0400991 return DWARF_CB_OK;
Masami Hiramatsue92b85e2010-02-25 08:35:50 -0500992
Masami Hiramatsu7d216352011-03-30 18:25:41 +0900993 /* Check declared file */
994 if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die)))
995 return DWARF_CB_OK;
996
Masami Hiramatsuf8da4b52016-09-24 00:34:57 +0900997 pr_debug("Matched function: %s [%lx]\n", dwarf_diename(sp_die),
998 (unsigned long)dwarf_dieoffset(sp_die));
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -0500999 pf->fname = dwarf_decl_file(sp_die);
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001000 if (pp->line) { /* Function relative line */
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001001 dwarf_decl_line(sp_die, &pf->lno);
1002 pf->lno += pp->line;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001003 param->retval = find_probe_point_by_line(pf);
Masami Hiramatsue1ecbbc2015-01-30 18:37:44 +09001004 } else if (die_is_func_instance(sp_die)) {
1005 /* Instances always have the entry address */
1006 dwarf_entrypc(sp_die, &pf->addr);
Masami Hiramatsu0ad45b32016-09-24 00:35:07 +09001007 /* But in some case the entry address is 0 */
1008 if (pf->addr == 0) {
1009 pr_debug("%s has no entry PC. Skipped\n",
1010 dwarf_diename(sp_die));
1011 param->retval = 0;
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001012 /* Real function */
Masami Hiramatsu0ad45b32016-09-24 00:35:07 +09001013 } else if (pp->lazy_line)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001014 param->retval = find_probe_point_lazy(sp_die, pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001015 else {
Ravi Bangoriae47392b2016-08-03 14:28:45 +05301016 skip_prologue(sp_die, pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001017 pf->addr += pp->offset;
1018 /* TODO: Check the address in this function */
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001019 param->retval = call_probe_finder(sp_die, pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001020 }
Masami Hiramatsu4c859352015-05-08 10:03:35 +09001021 } else if (!probe_conf.no_inlines) {
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001022 /* Inlined function: search instances */
Masami Hiramatsudb0d2c62011-08-11 20:03:11 +09001023 param->retval = die_walk_instances(sp_die,
1024 probe_point_inline_cb, (void *)pf);
Masami Hiramatsu4c859352015-05-08 10:03:35 +09001025 /* This could be a non-existed inline definition */
Masami Hiramatsuf8da4b52016-09-24 00:34:57 +09001026 if (param->retval == -ENOENT)
Masami Hiramatsu4c859352015-05-08 10:03:35 +09001027 param->retval = 0;
1028 }
1029
1030 /* We need to find other candidates */
1031 if (strisglob(pp->function) && param->retval >= 0) {
1032 param->retval = 0; /* We have to clear the result */
1033 return DWARF_CB_OK;
1034 }
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001035
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001036 return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001037}
1038
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001039static int find_probe_point_by_func(struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001040{
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001041 struct dwarf_callback_param _param = {.data = (void *)pf,
1042 .retval = 0};
1043 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0);
1044 return _param.retval;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001045}
1046
Lin Mingcd25f8b2011-03-25 16:27:48 +08001047struct pubname_callback_param {
1048 char *function;
1049 char *file;
1050 Dwarf_Die *cu_die;
1051 Dwarf_Die *sp_die;
1052 int found;
1053};
1054
1055static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
1056{
1057 struct pubname_callback_param *param = data;
1058
1059 if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) {
1060 if (dwarf_tag(param->sp_die) != DW_TAG_subprogram)
1061 return DWARF_CB_OK;
1062
Masami Hiramatsu4c859352015-05-08 10:03:35 +09001063 if (die_match_name(param->sp_die, param->function)) {
Lin Mingcd25f8b2011-03-25 16:27:48 +08001064 if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die))
1065 return DWARF_CB_OK;
1066
1067 if (param->file &&
1068 strtailcmp(param->file, dwarf_decl_file(param->sp_die)))
1069 return DWARF_CB_OK;
1070
1071 param->found = 1;
1072 return DWARF_CB_ABORT;
1073 }
1074 }
1075
1076 return DWARF_CB_OK;
1077}
1078
Hemant Kumar270bde12016-02-02 20:56:46 +05301079static int debuginfo__find_probe_location(struct debuginfo *dbg,
Masami Hiramatsuff741782011-06-27 16:27:39 +09001080 struct probe_finder *pf)
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001081{
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001082 struct perf_probe_point *pp = &pf->pev->point;
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001083 Dwarf_Off off, noff;
1084 size_t cuhl;
1085 Dwarf_Die *diep;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001086 int ret = 0;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001087
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001088 off = 0;
Masami Hiramatsu5a622572014-02-06 05:32:09 +00001089 pf->lcache = intlist__new(NULL);
1090 if (!pf->lcache)
1091 return -ENOMEM;
Lin Mingcd25f8b2011-03-25 16:27:48 +08001092
1093 /* Fastpath: lookup by function name from .debug_pubnames section */
Masami Hiramatsu4c859352015-05-08 10:03:35 +09001094 if (pp->function && !strisglob(pp->function)) {
Lin Mingcd25f8b2011-03-25 16:27:48 +08001095 struct pubname_callback_param pubname_param = {
1096 .function = pp->function,
1097 .file = pp->file,
1098 .cu_die = &pf->cu_die,
1099 .sp_die = &pf->sp_die,
Lin Ming2b348a72011-04-29 08:41:57 +00001100 .found = 0,
Lin Mingcd25f8b2011-03-25 16:27:48 +08001101 };
1102 struct dwarf_callback_param probe_param = {
1103 .data = pf,
1104 };
1105
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001106 dwarf_getpubnames(dbg->dbg, pubname_search_cb,
Masami Hiramatsuff741782011-06-27 16:27:39 +09001107 &pubname_param, 0);
Lin Mingcd25f8b2011-03-25 16:27:48 +08001108 if (pubname_param.found) {
1109 ret = probe_point_search_cb(&pf->sp_die, &probe_param);
1110 if (ret)
1111 goto found;
1112 }
1113 }
1114
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001115 /* Loop on CUs (Compilation Unit) */
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001116 while (!dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001117 /* Get the DIE(Debugging Information Entry) of this CU */
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001118 diep = dwarf_offdie(dbg->dbg, off + cuhl, &pf->cu_die);
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001119 if (!diep)
1120 continue;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001121
1122 /* Check if target file is included. */
1123 if (pp->file)
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001124 pf->fname = cu_find_realpath(&pf->cu_die, pp->file);
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001125 else
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001126 pf->fname = NULL;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001127
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001128 if (!pp->file || pf->fname) {
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001129 if (pp->function)
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001130 ret = find_probe_point_by_func(pf);
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001131 else if (pp->lazy_line)
He Kuangf19e80c2015-04-13 19:41:30 +08001132 ret = find_probe_point_lazy(&pf->cu_die, pf);
Masami Hiramatsub0ef0732009-10-27 16:43:19 -04001133 else {
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001134 pf->lno = pp->line;
1135 ret = find_probe_point_by_line(pf);
Masami Hiramatsub0ef0732009-10-27 16:43:19 -04001136 }
Arnaldo Carvalho de Melo8635bf62011-02-22 06:56:18 -03001137 if (ret < 0)
Arnaldo Carvalho de Melofbee6322011-02-21 13:23:57 -03001138 break;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001139 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001140 off = noff;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001141 }
Lin Mingcd25f8b2011-03-25 16:27:48 +08001142
1143found:
Masami Hiramatsu5a622572014-02-06 05:32:09 +00001144 intlist__delete(pf->lcache);
1145 pf->lcache = NULL;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001146
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001147 return ret;
1148}
1149
Hemant Kumar270bde12016-02-02 20:56:46 +05301150/* Find probe points from debuginfo */
1151static int debuginfo__find_probes(struct debuginfo *dbg,
1152 struct probe_finder *pf)
1153{
1154 int ret = 0;
Hemant Kumar270bde12016-02-02 20:56:46 +05301155 Elf *elf;
1156 GElf_Ehdr ehdr;
Hemant Kumar270bde12016-02-02 20:56:46 +05301157
1158 if (pf->cfi_eh || pf->cfi_dbg)
1159 return debuginfo__find_probe_location(dbg, pf);
1160
1161 /* Get the call frame information from this dwarf */
1162 elf = dwarf_getelf(dbg->dbg);
1163 if (elf == NULL)
1164 return -EINVAL;
1165
1166 if (gelf_getehdr(elf, &ehdr) == NULL)
1167 return -EINVAL;
1168
Masami Hiramatsu293d5b42016-08-26 01:24:57 +09001169 pf->machine = ehdr.e_machine;
Hemant Kumar270bde12016-02-02 20:56:46 +05301170
Masami Hiramatsu293d5b42016-08-26 01:24:57 +09001171#if _ELFUTILS_PREREQ(0, 142)
1172 do {
1173 GElf_Shdr shdr;
1174
1175 if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) &&
1176 shdr.sh_type == SHT_PROGBITS)
1177 pf->cfi_eh = dwarf_getcfi_elf(elf);
1178
1179 pf->cfi_dbg = dwarf_getcfi(dbg->dbg);
1180 } while (0);
Hemant Kumar270bde12016-02-02 20:56:46 +05301181#endif
1182
1183 ret = debuginfo__find_probe_location(dbg, pf);
1184 return ret;
1185}
1186
Masami Hiramatsu7969ec72013-10-11 16:10:23 +09001187struct local_vars_finder {
1188 struct probe_finder *pf;
1189 struct perf_probe_arg *args;
Masami Hiramatsuf8bffbf2015-05-06 21:46:53 +09001190 bool vars;
Masami Hiramatsu7969ec72013-10-11 16:10:23 +09001191 int max_args;
1192 int nargs;
1193 int ret;
1194};
1195
1196/* Collect available variables in this scope */
1197static int copy_variables_cb(Dwarf_Die *die_mem, void *data)
1198{
1199 struct local_vars_finder *vf = data;
Masami Hiramatsu3d918a12013-10-11 16:10:26 +09001200 struct probe_finder *pf = vf->pf;
Masami Hiramatsu7969ec72013-10-11 16:10:23 +09001201 int tag;
1202
1203 tag = dwarf_tag(die_mem);
1204 if (tag == DW_TAG_formal_parameter ||
Masami Hiramatsuf8bffbf2015-05-06 21:46:53 +09001205 (tag == DW_TAG_variable && vf->vars)) {
Masami Hiramatsu7969ec72013-10-11 16:10:23 +09001206 if (convert_variable_location(die_mem, vf->pf->addr,
Masami Hiramatsu3d918a12013-10-11 16:10:26 +09001207 vf->pf->fb_ops, &pf->sp_die,
Masami Hiramatsu293d5b42016-08-26 01:24:57 +09001208 pf->machine, NULL) == 0) {
Masami Hiramatsu7969ec72013-10-11 16:10:23 +09001209 vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem);
1210 if (vf->args[vf->nargs].var == NULL) {
1211 vf->ret = -ENOMEM;
1212 return DIE_FIND_CB_END;
1213 }
1214 pr_debug(" %s", vf->args[vf->nargs].var);
1215 vf->nargs++;
1216 }
1217 }
1218
1219 if (dwarf_haspc(die_mem, vf->pf->addr))
1220 return DIE_FIND_CB_CONTINUE;
1221 else
1222 return DIE_FIND_CB_SIBLING;
1223}
1224
1225static int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf,
1226 struct perf_probe_arg *args)
1227{
1228 Dwarf_Die die_mem;
1229 int i;
1230 int n = 0;
Masami Hiramatsuf8bffbf2015-05-06 21:46:53 +09001231 struct local_vars_finder vf = {.pf = pf, .args = args, .vars = false,
Masami Hiramatsu7969ec72013-10-11 16:10:23 +09001232 .max_args = MAX_PROBE_ARGS, .ret = 0};
1233
1234 for (i = 0; i < pf->pev->nargs; i++) {
1235 /* var never be NULL */
Masami Hiramatsuf8bffbf2015-05-06 21:46:53 +09001236 if (strcmp(pf->pev->args[i].var, PROBE_ARG_VARS) == 0)
1237 vf.vars = true;
1238 else if (strcmp(pf->pev->args[i].var, PROBE_ARG_PARAMS) != 0) {
Masami Hiramatsu7969ec72013-10-11 16:10:23 +09001239 /* Copy normal argument */
1240 args[n] = pf->pev->args[i];
1241 n++;
Masami Hiramatsuf8bffbf2015-05-06 21:46:53 +09001242 continue;
Masami Hiramatsu7969ec72013-10-11 16:10:23 +09001243 }
Masami Hiramatsuf8bffbf2015-05-06 21:46:53 +09001244 pr_debug("Expanding %s into:", pf->pev->args[i].var);
1245 vf.nargs = n;
1246 /* Special local variables */
1247 die_find_child(sc_die, copy_variables_cb, (void *)&vf,
1248 &die_mem);
1249 pr_debug(" (%d)\n", vf.nargs - n);
1250 if (vf.ret < 0)
1251 return vf.ret;
1252 n = vf.nargs;
Masami Hiramatsu7969ec72013-10-11 16:10:23 +09001253 }
1254 return n;
1255}
1256
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001257/* Add a found probe point into trace event list */
Masami Hiramatsu221d0612011-08-11 20:02:59 +09001258static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001259{
1260 struct trace_event_finder *tf =
1261 container_of(pf, struct trace_event_finder, pf);
Masami Hiramatsu6cca13b2015-10-01 01:41:37 +09001262 struct perf_probe_point *pp = &pf->pev->point;
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001263 struct probe_trace_event *tev;
Wang Nan092b1f02015-11-13 12:29:11 +00001264 struct perf_probe_arg *args = NULL;
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001265 int ret, i;
1266
1267 /* Check number of tevs */
1268 if (tf->ntevs == tf->max_tevs) {
1269 pr_warning("Too many( > %d) probe point found.\n",
1270 tf->max_tevs);
1271 return -ERANGE;
1272 }
1273 tev = &tf->tevs[tf->ntevs++];
1274
Masami Hiramatsu221d0612011-08-11 20:02:59 +09001275 /* Trace point should be converted from subprogram DIE */
Masami Hiramatsu576b5232013-09-25 22:16:16 +09001276 ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr,
Masami Hiramatsu6cca13b2015-10-01 01:41:37 +09001277 pp->retprobe, pp->function, &tev->point);
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001278 if (ret < 0)
Wang Nan092b1f02015-11-13 12:29:11 +00001279 goto end;
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001280
Masami Hiramatsu4c859352015-05-08 10:03:35 +09001281 tev->point.realname = strdup(dwarf_diename(sc_die));
Wang Nan092b1f02015-11-13 12:29:11 +00001282 if (!tev->point.realname) {
1283 ret = -ENOMEM;
1284 goto end;
1285 }
Masami Hiramatsu4c859352015-05-08 10:03:35 +09001286
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001287 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
1288 tev->point.offset);
1289
Masami Hiramatsu7969ec72013-10-11 16:10:23 +09001290 /* Expand special probe argument if exist */
1291 args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS);
Wang Nan092b1f02015-11-13 12:29:11 +00001292 if (args == NULL) {
1293 ret = -ENOMEM;
1294 goto end;
1295 }
Masami Hiramatsu7969ec72013-10-11 16:10:23 +09001296
1297 ret = expand_probe_args(sc_die, pf, args);
1298 if (ret < 0)
1299 goto end;
1300
1301 tev->nargs = ret;
1302 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
1303 if (tev->args == NULL) {
1304 ret = -ENOMEM;
1305 goto end;
1306 }
1307
1308 /* Find each argument */
1309 for (i = 0; i < tev->nargs; i++) {
1310 pf->pvar = &args[i];
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001311 pf->tvar = &tev->args[i];
Masami Hiramatsu221d0612011-08-11 20:02:59 +09001312 /* Variable should be found from scope DIE */
1313 ret = find_variable(sc_die, pf);
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001314 if (ret != 0)
Masami Hiramatsu7969ec72013-10-11 16:10:23 +09001315 break;
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001316 }
1317
Masami Hiramatsu7969ec72013-10-11 16:10:23 +09001318end:
Wang Nan092b1f02015-11-13 12:29:11 +00001319 if (ret) {
1320 clear_probe_trace_event(tev);
1321 tf->ntevs--;
1322 }
Masami Hiramatsu7969ec72013-10-11 16:10:23 +09001323 free(args);
1324 return ret;
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001325}
1326
1327/* Find probe_trace_events specified by perf_probe_event from debuginfo */
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001328int debuginfo__find_trace_events(struct debuginfo *dbg,
Masami Hiramatsuff741782011-06-27 16:27:39 +09001329 struct perf_probe_event *pev,
Masami Hiramatsuddb2f582015-05-08 10:03:31 +09001330 struct probe_trace_event **tevs)
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001331{
1332 struct trace_event_finder tf = {
1333 .pf = {.pev = pev, .callback = add_probe_trace_event},
Masami Hiramatsuddb2f582015-05-08 10:03:31 +09001334 .max_tevs = probe_conf.max_probes, .mod = dbg->mod};
Masami Hiramatsu0196e782015-11-13 12:29:10 +00001335 int ret, i;
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001336
1337 /* Allocate result tevs array */
Masami Hiramatsuddb2f582015-05-08 10:03:31 +09001338 *tevs = zalloc(sizeof(struct probe_trace_event) * tf.max_tevs);
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001339 if (*tevs == NULL)
1340 return -ENOMEM;
1341
1342 tf.tevs = *tevs;
1343 tf.ntevs = 0;
1344
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001345 ret = debuginfo__find_probes(dbg, &tf.pf);
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001346 if (ret < 0) {
Masami Hiramatsu0196e782015-11-13 12:29:10 +00001347 for (i = 0; i < tf.ntevs; i++)
1348 clear_probe_trace_event(&tf.tevs[i]);
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001349 zfree(tevs);
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001350 return ret;
1351 }
1352
1353 return (ret < 0) ? ret : tf.ntevs;
1354}
1355
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001356/* Collect available variables in this scope */
1357static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
1358{
1359 struct available_var_finder *af = data;
1360 struct variable_list *vl;
Masami Hiramatsubf4d5f22016-05-10 14:47:07 +09001361 struct strbuf buf = STRBUF_INIT;
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001362 int tag, ret;
1363
1364 vl = &af->vls[af->nvls - 1];
1365
1366 tag = dwarf_tag(die_mem);
1367 if (tag == DW_TAG_formal_parameter ||
1368 tag == DW_TAG_variable) {
1369 ret = convert_variable_location(die_mem, af->pf.addr,
Masami Hiramatsu3d918a12013-10-11 16:10:26 +09001370 af->pf.fb_ops, &af->pf.sp_die,
Masami Hiramatsu293d5b42016-08-26 01:24:57 +09001371 af->pf.machine, NULL);
He Kuang349e8d22015-05-11 09:25:03 +00001372 if (ret == 0 || ret == -ERANGE) {
1373 int ret2;
1374 bool externs = !af->child;
He Kuangfb9596d2015-05-11 09:25:02 +00001375
Masami Hiramatsubf4d5f22016-05-10 14:47:07 +09001376 if (strbuf_init(&buf, 64) < 0)
1377 goto error;
He Kuang349e8d22015-05-11 09:25:03 +00001378
1379 if (probe_conf.show_location_range) {
Masami Hiramatsubf4d5f22016-05-10 14:47:07 +09001380 if (!externs)
1381 ret2 = strbuf_add(&buf,
1382 ret ? "[INV]\t" : "[VAL]\t", 6);
1383 else
1384 ret2 = strbuf_add(&buf, "[EXT]\t", 6);
1385 if (ret2)
1386 goto error;
He Kuang349e8d22015-05-11 09:25:03 +00001387 }
1388
1389 ret2 = die_get_varname(die_mem, &buf);
1390
1391 if (!ret2 && probe_conf.show_location_range &&
1392 !externs) {
Masami Hiramatsubf4d5f22016-05-10 14:47:07 +09001393 if (strbuf_addch(&buf, '\t') < 0)
1394 goto error;
He Kuang349e8d22015-05-11 09:25:03 +00001395 ret2 = die_get_var_range(&af->pf.sp_die,
1396 die_mem, &buf);
1397 }
1398
1399 pr_debug("Add new var: %s\n", buf.buf);
1400 if (ret2 == 0) {
He Kuangfb9596d2015-05-11 09:25:02 +00001401 strlist__add(vl->vars,
1402 strbuf_detach(&buf, NULL));
Masami Hiramatsubf4d5f22016-05-10 14:47:07 +09001403 }
1404 strbuf_release(&buf);
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001405 }
1406 }
1407
Masami Hiramatsufb8c5a52010-10-21 19:13:35 +09001408 if (af->child && dwarf_haspc(die_mem, af->pf.addr))
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001409 return DIE_FIND_CB_CONTINUE;
1410 else
1411 return DIE_FIND_CB_SIBLING;
Masami Hiramatsubf4d5f22016-05-10 14:47:07 +09001412error:
1413 strbuf_release(&buf);
1414 pr_debug("Error in strbuf\n");
1415 return DIE_FIND_CB_END;
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001416}
1417
1418/* Add a found vars into available variables list */
Masami Hiramatsu221d0612011-08-11 20:02:59 +09001419static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf)
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001420{
1421 struct available_var_finder *af =
1422 container_of(pf, struct available_var_finder, pf);
Masami Hiramatsu6cca13b2015-10-01 01:41:37 +09001423 struct perf_probe_point *pp = &pf->pev->point;
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001424 struct variable_list *vl;
Masami Hiramatsuf182e3e2011-08-11 20:03:05 +09001425 Dwarf_Die die_mem;
1426 int ret;
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001427
1428 /* Check number of tevs */
1429 if (af->nvls == af->max_vls) {
1430 pr_warning("Too many( > %d) probe point found.\n", af->max_vls);
1431 return -ERANGE;
1432 }
1433 vl = &af->vls[af->nvls++];
1434
Masami Hiramatsu221d0612011-08-11 20:02:59 +09001435 /* Trace point should be converted from subprogram DIE */
Masami Hiramatsu576b5232013-09-25 22:16:16 +09001436 ret = convert_to_trace_point(&pf->sp_die, af->mod, pf->addr,
Masami Hiramatsu6cca13b2015-10-01 01:41:37 +09001437 pp->retprobe, pp->function, &vl->point);
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001438 if (ret < 0)
1439 return ret;
1440
1441 pr_debug("Probe point found: %s+%lu\n", vl->point.symbol,
1442 vl->point.offset);
1443
1444 /* Find local variables */
Arnaldo Carvalho de Melo4a77e212015-07-20 12:13:34 -03001445 vl->vars = strlist__new(NULL, NULL);
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001446 if (vl->vars == NULL)
1447 return -ENOMEM;
Masami Hiramatsufb8c5a52010-10-21 19:13:35 +09001448 af->child = true;
Masami Hiramatsu221d0612011-08-11 20:02:59 +09001449 die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem);
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001450
Masami Hiramatsufb8c5a52010-10-21 19:13:35 +09001451 /* Find external variables */
Masami Hiramatsuddb2f582015-05-08 10:03:31 +09001452 if (!probe_conf.show_ext_vars)
Masami Hiramatsufb8c5a52010-10-21 19:13:35 +09001453 goto out;
Masami Hiramatsuddb2f582015-05-08 10:03:31 +09001454 /* Don't need to search child DIE for external vars. */
Masami Hiramatsufb8c5a52010-10-21 19:13:35 +09001455 af->child = false;
Masami Hiramatsuf182e3e2011-08-11 20:03:05 +09001456 die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem);
Masami Hiramatsufb8c5a52010-10-21 19:13:35 +09001457
1458out:
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001459 if (strlist__empty(vl->vars)) {
1460 strlist__delete(vl->vars);
1461 vl->vars = NULL;
1462 }
1463
1464 return ret;
1465}
1466
Masami Hiramatsu69e96ea2014-06-06 07:13:59 +00001467/*
1468 * Find available variables at given probe point
1469 * Return the number of found probe points. Return 0 if there is no
1470 * matched probe point. Return <0 if an error occurs.
1471 */
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001472int debuginfo__find_available_vars_at(struct debuginfo *dbg,
Masami Hiramatsuff741782011-06-27 16:27:39 +09001473 struct perf_probe_event *pev,
Masami Hiramatsuddb2f582015-05-08 10:03:31 +09001474 struct variable_list **vls)
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001475{
1476 struct available_var_finder af = {
1477 .pf = {.pev = pev, .callback = add_available_vars},
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001478 .mod = dbg->mod,
Masami Hiramatsuddb2f582015-05-08 10:03:31 +09001479 .max_vls = probe_conf.max_probes};
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001480 int ret;
1481
1482 /* Allocate result vls array */
Masami Hiramatsuddb2f582015-05-08 10:03:31 +09001483 *vls = zalloc(sizeof(struct variable_list) * af.max_vls);
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001484 if (*vls == NULL)
1485 return -ENOMEM;
1486
1487 af.vls = *vls;
1488 af.nvls = 0;
1489
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001490 ret = debuginfo__find_probes(dbg, &af.pf);
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001491 if (ret < 0) {
1492 /* Free vlist for error */
1493 while (af.nvls--) {
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -03001494 zfree(&af.vls[af.nvls].point.symbol);
Arnaldo Carvalho de Melof5385652013-12-26 15:54:57 -03001495 strlist__delete(af.vls[af.nvls].vars);
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001496 }
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001497 zfree(vls);
Masami Hiramatsucf6eb482010-10-21 19:13:23 +09001498 return ret;
1499 }
1500
1501 return (ret < 0) ? ret : af.nvls;
Masami Hiramatsu4ea42b12009-10-08 17:17:38 -04001502}
1503
Masami Hiramatsu9b239a12015-10-01 01:41:33 +09001504/* For the kernel module, we need a special code to get a DIE */
Masami Hiramatsu613f0502017-01-11 15:01:57 +09001505int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs,
1506 bool adjust_offset)
Masami Hiramatsu9b239a12015-10-01 01:41:33 +09001507{
1508 int n, i;
1509 Elf32_Word shndx;
1510 Elf_Scn *scn;
1511 Elf *elf;
1512 GElf_Shdr mem, *shdr;
1513 const char *p;
1514
1515 elf = dwfl_module_getelf(dbg->mod, &dbg->bias);
1516 if (!elf)
1517 return -EINVAL;
1518
1519 /* Get the number of relocations */
1520 n = dwfl_module_relocations(dbg->mod);
1521 if (n < 0)
1522 return -ENOENT;
1523 /* Search the relocation related .text section */
1524 for (i = 0; i < n; i++) {
1525 p = dwfl_module_relocation_info(dbg->mod, i, &shndx);
1526 if (strcmp(p, ".text") == 0) {
1527 /* OK, get the section header */
1528 scn = elf_getscn(elf, shndx);
1529 if (!scn)
1530 return -ENOENT;
1531 shdr = gelf_getshdr(scn, &mem);
1532 if (!shdr)
1533 return -ENOENT;
1534 *offs = shdr->sh_addr;
Masami Hiramatsu613f0502017-01-11 15:01:57 +09001535 if (adjust_offset)
1536 *offs -= shdr->sh_offset;
Masami Hiramatsu9b239a12015-10-01 01:41:33 +09001537 }
1538 }
1539 return 0;
1540}
1541
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001542/* Reverse search */
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001543int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr,
Masami Hiramatsuff741782011-06-27 16:27:39 +09001544 struct perf_probe_point *ppt)
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001545{
1546 Dwarf_Die cudie, spdie, indie;
Masami Hiramatsue08cfd42013-09-30 18:21:44 +09001547 Dwarf_Addr _addr = 0, baseaddr = 0;
1548 const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp;
Masami Hiramatsu1d46ea22011-03-30 18:26:05 +09001549 int baseline = 0, lineno = 0, ret = 0;
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001550
Masami Hiramatsud2d4edb2017-01-11 14:59:38 +09001551 /* We always need to relocate the address for aranges */
Masami Hiramatsu613f0502017-01-11 15:01:57 +09001552 if (debuginfo__get_text_offset(dbg, &baseaddr, false) == 0)
Masami Hiramatsud2d4edb2017-01-11 14:59:38 +09001553 addr += baseaddr;
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001554 /* Find cu die */
Masami Hiramatsu0104fe62015-03-02 21:49:46 +09001555 if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) {
Masami Hiramatsu0e43e5d2010-12-17 22:12:11 +09001556 pr_warning("Failed to find debug information for address %lx\n",
1557 addr);
Masami Hiramatsu75ec5a22010-04-02 12:50:59 -04001558 ret = -EINVAL;
1559 goto end;
1560 }
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001561
Masami Hiramatsu1d46ea22011-03-30 18:26:05 +09001562 /* Find a corresponding line (filename and lineno) */
1563 cu_find_lineinfo(&cudie, addr, &fname, &lineno);
1564 /* Don't care whether it failed or not */
1565
1566 /* Find a corresponding function (name, baseline and baseaddr) */
Masami Hiramatsue0d153c2011-06-27 16:27:27 +09001567 if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) {
Masami Hiramatsu1d46ea22011-03-30 18:26:05 +09001568 /* Get function entry information */
Masami Hiramatsue08cfd42013-09-30 18:21:44 +09001569 func = basefunc = dwarf_diename(&spdie);
1570 if (!func ||
Masami Hiramatsu1d46ea22011-03-30 18:26:05 +09001571 dwarf_entrypc(&spdie, &baseaddr) != 0 ||
Masami Hiramatsue08cfd42013-09-30 18:21:44 +09001572 dwarf_decl_line(&spdie, &baseline) != 0) {
1573 lineno = 0;
Masami Hiramatsu1d46ea22011-03-30 18:26:05 +09001574 goto post;
Masami Hiramatsue08cfd42013-09-30 18:21:44 +09001575 }
Masami Hiramatsu1d46ea22011-03-30 18:26:05 +09001576
Masami Hiramatsu1b286bd2013-10-11 12:23:17 +00001577 fname = dwarf_decl_file(&spdie);
Masami Hiramatsue08cfd42013-09-30 18:21:44 +09001578 if (addr == (unsigned long)baseaddr) {
Masami Hiramatsu1d46ea22011-03-30 18:26:05 +09001579 /* Function entry - Relative line number is 0 */
1580 lineno = baseline;
Masami Hiramatsue08cfd42013-09-30 18:21:44 +09001581 goto post;
1582 }
1583
1584 /* Track down the inline functions step by step */
1585 while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr,
1586 &indie)) {
1587 /* There is an inline function */
Masami Hiramatsu1d46ea22011-03-30 18:26:05 +09001588 if (dwarf_entrypc(&indie, &_addr) == 0 &&
Masami Hiramatsue08cfd42013-09-30 18:21:44 +09001589 _addr == addr) {
Masami Hiramatsu1d46ea22011-03-30 18:26:05 +09001590 /*
1591 * addr is at an inline function entry.
1592 * In this case, lineno should be the call-site
Masami Hiramatsue08cfd42013-09-30 18:21:44 +09001593 * line number. (overwrite lineinfo)
Masami Hiramatsu1d46ea22011-03-30 18:26:05 +09001594 */
1595 lineno = die_get_call_lineno(&indie);
Masami Hiramatsue08cfd42013-09-30 18:21:44 +09001596 fname = die_get_call_file(&indie);
1597 break;
1598 } else {
Masami Hiramatsu1d46ea22011-03-30 18:26:05 +09001599 /*
1600 * addr is in an inline function body.
1601 * Since lineno points one of the lines
1602 * of the inline function, baseline should
1603 * be the entry line of the inline function.
1604 */
1605 tmp = dwarf_diename(&indie);
Masami Hiramatsue08cfd42013-09-30 18:21:44 +09001606 if (!tmp ||
1607 dwarf_decl_line(&indie, &baseline) != 0)
1608 break;
1609 func = tmp;
1610 spdie = indie;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001611 }
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001612 }
Masami Hiramatsue08cfd42013-09-30 18:21:44 +09001613 /* Verify the lineno and baseline are in a same file */
1614 tmp = dwarf_decl_file(&spdie);
1615 if (!tmp || strcmp(tmp, fname) != 0)
1616 lineno = 0;
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001617 }
1618
Masami Hiramatsu1d46ea22011-03-30 18:26:05 +09001619post:
1620 /* Make a relative line number or an offset */
1621 if (lineno)
1622 ppt->line = lineno - baseline;
Masami Hiramatsue08cfd42013-09-30 18:21:44 +09001623 else if (basefunc) {
Masami Hiramatsu1d46ea22011-03-30 18:26:05 +09001624 ppt->offset = addr - (unsigned long)baseaddr;
Masami Hiramatsue08cfd42013-09-30 18:21:44 +09001625 func = basefunc;
1626 }
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001627
Masami Hiramatsu1d46ea22011-03-30 18:26:05 +09001628 /* Duplicate strings */
1629 if (func) {
1630 ppt->function = strdup(func);
Masami Hiramatsu02b95da2010-04-12 13:17:56 -04001631 if (ppt->function == NULL) {
1632 ret = -ENOMEM;
1633 goto end;
1634 }
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001635 }
Masami Hiramatsu1d46ea22011-03-30 18:26:05 +09001636 if (fname) {
1637 ppt->file = strdup(fname);
1638 if (ppt->file == NULL) {
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001639 zfree(&ppt->function);
Masami Hiramatsu1d46ea22011-03-30 18:26:05 +09001640 ret = -ENOMEM;
1641 goto end;
1642 }
1643 }
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001644end:
Masami Hiramatsu1d46ea22011-03-30 18:26:05 +09001645 if (ret == 0 && (fname || func))
1646 ret = 1; /* Found a point */
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001647 return ret;
1648}
1649
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001650/* Add a line and store the src path */
1651static int line_range_add_line(const char *src, unsigned int lineno,
1652 struct line_range *lr)
1653{
Masami Hiramatsu7cf0b792010-07-09 18:28:59 +09001654 /* Copy source path */
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001655 if (!lr->path) {
Masami Hiramatsu7cf0b792010-07-09 18:28:59 +09001656 lr->path = strdup(src);
1657 if (lr->path == NULL)
1658 return -ENOMEM;
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001659 }
Masami Hiramatsu5a622572014-02-06 05:32:09 +00001660 return intlist__add(lr->line_list, lineno);
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001661}
1662
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +09001663static int line_range_walk_cb(const char *fname, int lineno,
Irina Tirdea1d037ca2012-09-11 01:15:03 +03001664 Dwarf_Addr addr __maybe_unused,
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +09001665 void *data)
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001666{
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +09001667 struct line_finder *lf = data;
Namhyung Kim202c7c12014-04-01 13:47:57 +09001668 int err;
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001669
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +09001670 if ((strtailcmp(fname, lf->fname) != 0) ||
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001671 (lf->lno_s > lineno || lf->lno_e < lineno))
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +09001672 return 0;
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001673
Namhyung Kim202c7c12014-04-01 13:47:57 +09001674 err = line_range_add_line(fname, lineno, lf->lr);
1675 if (err < 0 && err != -EEXIST)
1676 return err;
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001677
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +09001678 return 0;
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001679}
Masami Hiramatsufb1587d2010-03-16 18:06:19 -04001680
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001681/* Find line range from its line number */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001682static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001683{
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +09001684 int ret;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001685
Masami Hiramatsu4cc9cec2011-01-13 21:45:58 +09001686 ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf);
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001687
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001688 /* Update status */
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001689 if (ret >= 0)
Masami Hiramatsu5a622572014-02-06 05:32:09 +00001690 if (!intlist__empty(lf->lr->line_list))
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001691 ret = lf->found = 1;
1692 else
1693 ret = 0; /* Lines are not found */
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001694 else {
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001695 zfree(&lf->lr->path);
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001696 }
Masami Hiramatsuf6c903f2010-04-14 18:40:07 -04001697 return ret;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001698}
1699
Masami Hiramatsu161a26b2010-02-25 08:35:57 -05001700static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
1701{
Masami Hiramatsu182c2282014-04-02 14:48:31 +09001702 int ret = find_line_range_by_line(in_die, data);
Masami Hiramatsu36c0c582011-08-11 20:02:47 +09001703
1704 /*
1705 * We have to check all instances of inlined function, because
1706 * some execution paths can be optimized out depends on the
Masami Hiramatsu182c2282014-04-02 14:48:31 +09001707 * function argument of instances. However, if an error occurs,
1708 * it should be handled by the caller.
Masami Hiramatsu36c0c582011-08-11 20:02:47 +09001709 */
Masami Hiramatsu182c2282014-04-02 14:48:31 +09001710 return ret < 0 ? ret : 0;
Masami Hiramatsu161a26b2010-02-25 08:35:57 -05001711}
1712
Masami Hiramatsu0dbb1ca2012-04-23 12:24:36 +09001713/* Search function definition from function name */
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001714static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001715{
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001716 struct dwarf_callback_param *param = data;
1717 struct line_finder *lf = param->data;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001718 struct line_range *lr = lf->lr;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001719
Masami Hiramatsu7d216352011-03-30 18:25:41 +09001720 /* Check declared file */
1721 if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die)))
1722 return DWARF_CB_OK;
1723
Masami Hiramatsu0dbb1ca2012-04-23 12:24:36 +09001724 if (die_is_func_def(sp_die) &&
Masami Hiramatsu4c859352015-05-08 10:03:35 +09001725 die_match_name(sp_die, lr->function)) {
Masami Hiramatsue92b85e2010-02-25 08:35:50 -05001726 lf->fname = dwarf_decl_file(sp_die);
1727 dwarf_decl_line(sp_die, &lr->offset);
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001728 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001729 lf->lno_s = lr->offset + lr->start;
Masami Hiramatsud3b63d72010-04-14 18:39:42 -04001730 if (lf->lno_s < 0) /* Overflow */
1731 lf->lno_s = INT_MAX;
1732 lf->lno_e = lr->offset + lr->end;
1733 if (lf->lno_e < 0) /* Overflow */
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001734 lf->lno_e = INT_MAX;
Masami Hiramatsud3b63d72010-04-14 18:39:42 -04001735 pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001736 lr->start = lf->lno_s;
1737 lr->end = lf->lno_e;
Masami Hiramatsue1ecbbc2015-01-30 18:37:44 +09001738 if (!die_is_func_instance(sp_die))
Masami Hiramatsudb0d2c62011-08-11 20:03:11 +09001739 param->retval = die_walk_instances(sp_die,
1740 line_range_inline_cb, lf);
1741 else
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001742 param->retval = find_line_range_by_line(sp_die, lf);
1743 return DWARF_CB_ABORT;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001744 }
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001745 return DWARF_CB_OK;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001746}
1747
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001748static int find_line_range_by_func(struct line_finder *lf)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001749{
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001750 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
1751 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, &param, 0);
1752 return param.retval;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001753}
1754
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001755int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001756{
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001757 struct line_finder lf = {.lr = lr, .found = 0};
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001758 int ret = 0;
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001759 Dwarf_Off off = 0, noff;
1760 size_t cuhl;
1761 Dwarf_Die *diep;
Masami Hiramatsu6a330a32010-07-09 18:29:11 +09001762 const char *comp_dir;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001763
Lin Mingcd25f8b2011-03-25 16:27:48 +08001764 /* Fastpath: lookup by function name from .debug_pubnames section */
1765 if (lr->function) {
1766 struct pubname_callback_param pubname_param = {
1767 .function = lr->function, .file = lr->file,
1768 .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0};
1769 struct dwarf_callback_param line_range_param = {
1770 .data = (void *)&lf, .retval = 0};
1771
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001772 dwarf_getpubnames(dbg->dbg, pubname_search_cb,
Masami Hiramatsuff741782011-06-27 16:27:39 +09001773 &pubname_param, 0);
Lin Mingcd25f8b2011-03-25 16:27:48 +08001774 if (pubname_param.found) {
1775 line_range_search_cb(&lf.sp_die, &line_range_param);
1776 if (lf.found)
1777 goto found;
1778 }
1779 }
1780
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001781 /* Loop on CUs (Compilation Unit) */
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001782 while (!lf.found && ret >= 0) {
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001783 if (dwarf_nextcu(dbg->dbg, off, &noff, &cuhl,
Masami Hiramatsuff741782011-06-27 16:27:39 +09001784 NULL, NULL, NULL) != 0)
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001785 break;
1786
1787 /* Get the DIE(Debugging Information Entry) of this CU */
Arnaldo Carvalho de Melo316c7132013-11-05 15:32:36 -03001788 diep = dwarf_offdie(dbg->dbg, off + cuhl, &lf.cu_die);
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001789 if (!diep)
1790 continue;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001791
1792 /* Check if target file is included. */
1793 if (lr->file)
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001794 lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001795 else
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001796 lf.fname = 0;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001797
Masami Hiramatsu2a9c8c32010-02-25 08:36:12 -05001798 if (!lr->file || lf.fname) {
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001799 if (lr->function)
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001800 ret = find_line_range_by_func(&lf);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001801 else {
1802 lf.lno_s = lr->start;
Masami Hiramatsud3b63d72010-04-14 18:39:42 -04001803 lf.lno_e = lr->end;
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001804 ret = find_line_range_by_line(NULL, &lf);
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001805 }
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001806 }
Masami Hiramatsu804b3602010-02-25 08:35:42 -05001807 off = noff;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001808 }
Masami Hiramatsu6a330a32010-07-09 18:29:11 +09001809
Lin Mingcd25f8b2011-03-25 16:27:48 +08001810found:
Masami Hiramatsu6a330a32010-07-09 18:29:11 +09001811 /* Store comp_dir */
1812 if (lf.found) {
1813 comp_dir = cu_get_comp_dir(&lf.cu_die);
1814 if (comp_dir) {
1815 lr->comp_dir = strdup(comp_dir);
1816 if (!lr->comp_dir)
1817 ret = -ENOMEM;
1818 }
1819 }
1820
Masami Hiramatsu7cf0b792010-07-09 18:28:59 +09001821 pr_debug("path: %s\n", lr->path);
Masami Hiramatsub55a87a2010-04-12 13:17:35 -04001822 return (ret < 0) ? ret : lf.found;
Masami Hiramatsu631c9de2010-01-06 09:45:34 -05001823}
1824
Naohiro Aota09ed8972015-03-13 14:18:40 +09001825/*
1826 * Find a src file from a DWARF tag path. Prepend optional source path prefix
1827 * and chop off leading directories that do not exist. Result is passed back as
1828 * a newly allocated path on success.
1829 * Return 0 if file was found and readable, -errno otherwise.
1830 */
1831int get_real_path(const char *raw_path, const char *comp_dir,
1832 char **new_path)
1833{
1834 const char *prefix = symbol_conf.source_prefix;
1835
1836 if (!prefix) {
1837 if (raw_path[0] != '/' && comp_dir)
1838 /* If not an absolute path, try to use comp_dir */
1839 prefix = comp_dir;
1840 else {
1841 if (access(raw_path, R_OK) == 0) {
1842 *new_path = strdup(raw_path);
1843 return *new_path ? 0 : -ENOMEM;
1844 } else
1845 return -errno;
1846 }
1847 }
1848
1849 *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2));
1850 if (!*new_path)
1851 return -ENOMEM;
1852
1853 for (;;) {
1854 sprintf(*new_path, "%s/%s", prefix, raw_path);
1855
1856 if (access(*new_path, R_OK) == 0)
1857 return 0;
1858
1859 if (!symbol_conf.source_prefix) {
1860 /* In case of searching comp_dir, don't retry */
1861 zfree(new_path);
1862 return -errno;
1863 }
1864
1865 switch (errno) {
1866 case ENAMETOOLONG:
1867 case ENOENT:
1868 case EROFS:
1869 case EFAULT:
1870 raw_path = strchr(++raw_path, '/');
1871 if (!raw_path) {
1872 zfree(new_path);
1873 return -ENOENT;
1874 }
1875 continue;
1876
1877 default:
1878 zfree(new_path);
1879 return -errno;
1880 }
1881 }
1882}