probe-finder.c 15.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
/*
 * 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.
 *
 */

#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
34

35 36
#include "event.h"
#include "debug.h"
37
#include "util.h"
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
#include "probe-finder.h"


/*
 * Generic dwarf analysis helpers
 */

#define X86_32_MAX_REGS 8
const char *x86_32_regs_table[X86_32_MAX_REGS] = {
	"%ax",
	"%cx",
	"%dx",
	"%bx",
	"$stack",	/* Stack address instead of %sp */
	"%bp",
	"%si",
	"%di",
};

#define X86_64_MAX_REGS 16
const char *x86_64_regs_table[X86_64_MAX_REGS] = {
	"%ax",
	"%dx",
	"%cx",
	"%bx",
	"%si",
	"%di",
	"%bp",
	"%sp",
	"%r8",
	"%r9",
	"%r10",
	"%r11",
	"%r12",
	"%r13",
	"%r14",
	"%r15",
};

/* TODO: switching by dwarf address size */
#ifdef __x86_64__
#define ARCH_MAX_REGS X86_64_MAX_REGS
#define arch_regs_table x86_64_regs_table
#else
#define ARCH_MAX_REGS X86_32_MAX_REGS
#define arch_regs_table x86_32_regs_table
#endif

/* Return architecture dependent register string (for kprobe-tracer) */
static const char *get_arch_regstr(unsigned int n)
{
	return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL;
}

/*
 * Compare the tail of two strings.
 * Return 0 if whole of either string is same as another's tail part.
 */
static int strtailcmp(const char *s1, const char *s2)
{
	int i1 = strlen(s1);
	int i2 = strlen(s2);
100
	while (--i1 >= 0 && --i2 >= 0) {
101 102 103 104 105 106 107
		if (s1[i1] != s2[i2])
			return s1[i1] - s2[i2];
	}
	return 0;
}

/* Find the fileno of the target file. */
108
static int cu_find_fileno(Dwarf_Die *cu_die, const char *fname)
109
{
110 111 112
	Dwarf_Files *files;
	size_t nfiles, i;
	const char *src;
113 114 115
	int ret;

	if (!fname)
116
		return -EINVAL;
117

118 119 120 121 122 123 124 125
	ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
	if (ret == 0) {
		for (i = 0; i < nfiles; i++) {
			src = dwarf_filesrc(files, i, NULL, NULL);
			if (strtailcmp(src, fname) == 0) {
				ret = (int)i;	/*???: +1 or not?*/
				break;
			}
126
		}
127 128
		if (ret)
			pr_debug("found fno: %d\n", ret);
129
	}
130
	return ret;
131 132
}

133 134 135 136 137 138
struct __addr_die_search_param {
	Dwarf_Addr	addr;
	Dwarf_Die	*die_mem;
};

static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
139
{
140
	struct __addr_die_search_param *ad = data;
141

142 143 144 145 146 147 148
	if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
	    dwarf_haspc(fn_die, ad->addr)) {
		memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
		return DWARF_CB_ABORT;
	}
	return DWARF_CB_OK;
}
149

150 151 152 153 154 155 156 157 158 159 160 161
/* Search a real subprogram including this line, */
static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
					  Dwarf_Die *die_mem)
{
	struct __addr_die_search_param ad;
	ad.addr = addr;
	ad.die_mem = die_mem;
	/* dwarf_getscopes can't find subprogram. */
	if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
		return NULL;
	else
		return die_mem;
162 163
}

164
/* Compare diename and tname */
165
static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
166
{
167 168 169 170
	const char *name;
	name = dwarf_diename(dw_die);
	DIE_IF(name == NULL);
	return strcmp(tname, name);
171 172
}

173 174
/* Get entry pc(or low pc, 1st entry of ranges)  of the die */
static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
175
{
176
	Dwarf_Addr epc;
177 178
	int ret;

179 180 181
	ret = dwarf_entrypc(dw_die, &epc);
	DIE_IF(ret == -1);
	return epc;
182 183
}

184 185 186
/* Get a variable die */
static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
				    Dwarf_Die *die_mem)
187
{
188 189
	Dwarf_Die child_die;
	int tag;
190 191
	int ret;

192 193 194
	ret = dwarf_child(sp_die, die_mem);
	if (ret != 0)
		return NULL;
195

196 197 198 199 200 201
	do {
		tag = dwarf_tag(die_mem);
		if ((tag == DW_TAG_formal_parameter ||
		     tag == DW_TAG_variable) &&
		    (die_compare_name(die_mem, name) == 0))
			return die_mem;
202

203 204 205 206 207
		if (die_find_variable(die_mem, name, &child_die)) {
			memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
			return die_mem;
		}
	} while (dwarf_siblingof(die_mem, die_mem) == 0);
208

209
	return NULL;
210 211 212 213 214 215 216
}

/*
 * Probe finder related functions
 */

/* Show a location */
217
static void show_location(Dwarf_Op *op, struct probe_finder *pf)
218
{
219 220
	unsigned int regn;
	Dwarf_Word offs = 0;
221 222 223
	int deref = 0, ret;
	const char *regs;

224
	/* TODO: support CFA */
225
	/* If this is based on frame buffer, set the offset */
226 227 228
	if (op->atom == DW_OP_fbreg) {
		if (pf->fb_ops == NULL)
			die("The attribute of frame base is not supported.\n");
229
		deref = 1;
230 231 232
		offs = op->number;
		op = &pf->fb_ops[0];
	}
233

234 235 236
	if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
		regn = op->atom - DW_OP_breg0;
		offs += op->number;
237
		deref = 1;
238 239 240 241 242
	} 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;
243
		deref = 1;
244 245
	} else if (op->atom == DW_OP_regx) {
		regn = op->number;
246
	} else
247
		die("DW_OP %d is not supported.", op->atom);
248 249 250

	regs = get_arch_regstr(regn);
	if (!regs)
251
		die("%u exceeds max register number.", regn);
252 253

	if (deref)
254 255
		ret = snprintf(pf->buf, pf->len, " %s=+%ju(%s)",
			       pf->var, (uintmax_t)offs, regs);
256 257
	else
		ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
258 259
	DIE_IF(ret < 0);
	DIE_IF(ret >= pf->len);
260 261 262
}

/* Show a variables in kprobe event format */
263
static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
264 265
{
	Dwarf_Attribute attr;
266 267
	Dwarf_Op *expr;
	size_t nexpr;
268 269
	int ret;

270
	if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
271
		goto error;
272 273 274 275
	/* TODO: handle more than 1 exprs */
	ret = dwarf_getlocation_addr(&attr, (pf->addr - pf->cu_base),
				     &expr, &nexpr, 1);
	if (ret <= 0 || nexpr == 0)
276
		goto error;
277 278 279

	show_location(expr, pf);
	/* *expr will be cached in libdw. Don't free it. */
280 281
	return ;
error:
282
	/* TODO: Support const_value */
283
	die("Failed to find the location of %s at this address.\n"
284
	    " Perhaps, it has been optimized out.", pf->var);
285 286 287
}

/* Find a variable in a subprogram die */
288
static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
289 290
{
	int ret;
291
	Dwarf_Die vr_die;
292

293
	/* TODO: Support struct members and arrays */
294 295 296
	if (!is_c_varname(pf->var)) {
		/* Output raw parameters */
		ret = snprintf(pf->buf, pf->len, " %s", pf->var);
297 298
		DIE_IF(ret < 0);
		DIE_IF(ret >= pf->len);
299 300 301
		return ;
	}

302
	pr_debug("Searching '%s' variable in context.\n", pf->var);
303
	/* Search child die for local variables and parameters. */
304
	if (!die_find_variable(sp_die, pf->var, &vr_die))
305
		die("Failed to find '%s' in this function.", pf->var);
306 307

	show_variable(&vr_die, pf);
308 309 310
}

/* Show a probe point to output buffer */
311
static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
312 313
{
	struct probe_point *pp = pf->pp;
314 315
	Dwarf_Addr eaddr;
	Dwarf_Die die_mem;
316
	const char *name;
317 318
	char tmp[MAX_PROBE_BUFFER];
	int ret, i, len;
319 320
	Dwarf_Attribute fb_attr;
	size_t nops;
321

322 323 324 325 326 327 328 329
	/* If no real subprogram, find a real one */
	if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
		sp_die = die_get_real_subprogram(&pf->cu_die,
						 pf->addr, &die_mem);
		if (!sp_die)
			die("Probe point is not found in subprograms.");
	}

330
	/* Output name of probe point */
331 332
	name = dwarf_diename(sp_die);
	if (name) {
333 334 335
		dwarf_entrypc(sp_die, &eaddr);
		ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name,
				(unsigned long)(pf->addr - eaddr));
336 337 338
		/* Copy the function name if possible */
		if (!pp->function) {
			pp->function = strdup(name);
339
			pp->offset = (size_t)(pf->addr - eaddr);
340
		}
341 342
	} else {
		/* This function has no name. */
343 344
		ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx",
			       (uintmax_t)pf->addr);
345 346 347
		if (!pp->function) {
			/* TODO: Use _stext */
			pp->function = strdup("");
348
			pp->offset = (size_t)pf->addr;
349
		}
350
	}
351 352
	DIE_IF(ret < 0);
	DIE_IF(ret >= MAX_PROBE_BUFFER);
353
	len = ret;
354
	pr_debug("Probe point found: %s\n", tmp);
355

356 357 358 359 360 361 362
	/* Get the frame base attribute/ops */
	dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
	ret = dwarf_getlocation_addr(&fb_attr, (pf->addr - pf->cu_base),
				     &pf->fb_ops, &nops, 1);
	if (ret <= 0 || nops == 0)
		pf->fb_ops = NULL;

363
	/* Find each argument */
364
	/* TODO: use dwarf_cfi_addrframe */
365 366 367 368 369 370 371
	for (i = 0; i < pp->nr_args; i++) {
		pf->var = pp->args[i];
		pf->buf = &tmp[len];
		pf->len = MAX_PROBE_BUFFER - len;
		find_variable(sp_die, pf);
		len += strlen(pf->buf);
	}
372 373 374

	/* *pf->fb_ops will be cached in libdw. Don't free it. */
	pf->fb_ops = NULL;
375 376 377 378 379 380

	pp->probes[pp->found] = strdup(tmp);
	pp->found++;
}

/* Find probe point from its line number */
381
static void find_probe_point_by_line(struct probe_finder *pf)
382
{
383 384 385
	Dwarf_Lines *lines;
	Dwarf_Line *line;
	size_t nlines, i;
386
	Dwarf_Addr addr;
387
	int lineno;
388 389
	int ret;

390 391
	ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
	DIE_IF(ret != 0);
392

393 394 395
	for (i = 0; i < nlines; i++) {
		line = dwarf_onesrcline(lines, i);
		dwarf_lineno(line, &lineno);
396
		if (lineno != pf->lno)
397 398
			continue;

399 400 401
		/* TODO: Get fileno from line, but how? */
		if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
			continue;
402

403 404 405 406
		ret = dwarf_lineaddr(line, &addr);
		DIE_IF(ret != 0);
		pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
			 (int)i, lineno, (uintmax_t)addr);
407
		pf->addr = addr;
408

409
		show_probe_point(NULL, pf);
410 411 412 413
		/* Continuing, because target line might be inlined. */
	}
}

414 415 416 417 418 419 420 421 422 423 424 425 426
static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
{
	struct probe_finder *pf = (struct probe_finder *)data;
	struct probe_point *pp = pf->pp;

	/* Get probe address */
	pf->addr = die_get_entrypc(in_die);
	pf->addr += pp->offset;
	pr_debug("found inline addr: 0x%jx\n", (uintmax_t)pf->addr);

	show_probe_point(in_die, pf);
	return DWARF_CB_OK;
}
427

428
/* Search function from function name */
429
static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
430 431 432 433
{
	struct probe_finder *pf = (struct probe_finder *)data;
	struct probe_point *pp = pf->pp;

434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
	/* Check tag and diename */
	if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
	    die_compare_name(sp_die, pp->function) != 0)
		return 0;

	if (pp->line) { /* Function relative line */
		pf->fname = dwarf_decl_file(sp_die);
		dwarf_decl_line(sp_die, &pf->lno);
		pf->lno += pp->line;
		find_probe_point_by_line(pf);
	} else if (!dwarf_func_inline(sp_die)) {
		/* Real function */
		pf->addr = die_get_entrypc(sp_die);
		pf->addr += pp->offset;
		/* TODO: Check the address in this function */
		show_probe_point(sp_die, pf);
	} else
		/* Inlined function: search instances */
		dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf);

	return 1; /* Exit; no same symbol in this CU. */
455 456
}

457
static void find_probe_point_by_func(struct probe_finder *pf)
458
{
459
	dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0);
460 461 462
}

/* Find a probe point */
463
int find_probe_point(int fd, struct probe_point *pp)
464 465
{
	struct probe_finder pf = {.pp = pp};
466 467 468 469 470 471 472 473 474
	int ret;
	Dwarf_Off off, noff;
	size_t cuhl;
	Dwarf_Die *diep;
	Dwarf *dbg;
	int fno = 0;

	dbg = dwarf_begin(fd, DWARF_C_READ);
	if (!dbg)
475
		return -ENOENT;
476 477

	pp->found = 0;
478 479 480
	off = 0;
	/* Loop on CUs (Compilation Unit) */
	while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
481
		/* Get the DIE(Debugging Information Entry) of this CU */
482 483 484
		diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
		if (!diep)
			continue;
485 486 487

		/* Check if target file is included. */
		if (pp->file)
488 489 490
			fno = cu_find_fileno(&pf.cu_die, pp->file);
		else
			fno = 0;
491

492
		if (!pp->file || fno) {
493
			/* Save CU base address (for frame_base) */
494 495
			ret = dwarf_lowpc(&pf.cu_die, &pf.cu_base);
			if (ret != 0)
496 497
				pf.cu_base = 0;
			if (pp->function)
498
				find_probe_point_by_func(&pf);
499 500
			else {
				pf.lno = pp->line;
501
				find_probe_point_by_line(&pf);
502
			}
503
		}
504
		off = noff;
505
	}
506
	dwarf_end(dbg);
507 508 509 510

	return pp->found;
}

511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538

static void line_range_add_line(struct line_range *lr, unsigned int line)
{
	struct line_node *ln;
	struct list_head *p;

	/* Reverse search, because new line will be the last one */
	list_for_each_entry_reverse(ln, &lr->line_list, list) {
		if (ln->line < line) {
			p = &ln->list;
			goto found;
		} else if (ln->line == line)	/* Already exist */
			return ;
	}
	/* List is empty, or the smallest entry */
	p = &lr->line_list;
found:
	pr_debug("Debug: add a line %u\n", line);
	ln = zalloc(sizeof(struct line_node));
	DIE_IF(ln == NULL);
	ln->line = line;
	INIT_LIST_HEAD(&ln->list);
	list_add(&ln->list, p);
}

/* Find line range from its line number */
static void find_line_range_by_line(struct line_finder *lf)
{
539 540 541
	Dwarf_Lines *lines;
	Dwarf_Line *line;
	size_t nlines, i;
542
	Dwarf_Addr addr;
543
	int lineno;
544
	int ret;
545
	const char *src;
546

547
	INIT_LIST_HEAD(&lf->lr->line_list);
548 549
	ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines);
	DIE_IF(ret != 0);
550

551 552 553 554
	for (i = 0; i < nlines; i++) {
		line = dwarf_onesrcline(lines, i);
		dwarf_lineno(line, &lineno);
		if (lf->lno_s > lineno || lf->lno_e < lineno)
555 556
			continue;

557 558 559
		/* TODO: Get fileno from line, but how? */
		src = dwarf_linesrc(line, NULL, NULL);
		if (strtailcmp(src, lf->fname) != 0)
560 561 562 563
			continue;

		/* Filter line in the function address range */
		if (lf->addr_s && lf->addr_e) {
564 565
			ret = dwarf_lineaddr(line, &addr);
			DIE_IF(ret != 0);
566 567 568
			if (lf->addr_s > addr || lf->addr_e <= addr)
				continue;
		}
569 570 571
		/* Copy real path */
		if (!lf->lr->path)
			lf->lr->path = strdup(src);
572 573
		line_range_add_line(lf->lr, (unsigned int)lineno);
	}
574
	/* Update status */
575 576
	if (!list_empty(&lf->lr->line_list))
		lf->found = 1;
577 578 579 580
	else {
		free(lf->lr->path);
		lf->lr->path = NULL;
	}
581 582 583
}

/* Search function from function name */
584
static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
585 586 587 588 589
{
	struct line_finder *lf = (struct line_finder *)data;
	struct line_range *lr = lf->lr;
	int ret;

590 591
	if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
	    die_compare_name(sp_die, lr->function) == 0) {
592
		/* Get the address range of this function */
593
		ret = dwarf_highpc(sp_die, &lf->addr_e);
594
		if (ret == 0)
595
			ret = dwarf_lowpc(sp_die, &lf->addr_s);
596
		if (ret != 0) {
597 598 599 600
			lf->addr_s = 0;
			lf->addr_e = 0;
		}

601 602
		lf->fname = dwarf_decl_file(sp_die);
		dwarf_decl_line(sp_die, &lr->offset);
603
		pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
604 605
		lf->lno_s = lr->offset + lr->start;
		if (!lr->end)
606
			lf->lno_e = INT_MAX;
607 608 609 610 611 612 613 614 615 616 617 618
		else
			lf->lno_e = lr->offset + lr->end;
		lr->start = lf->lno_s;
		lr->end = lf->lno_e;
		find_line_range_by_line(lf);
		return 1;
	}
	return 0;
}

static void find_line_range_by_func(struct line_finder *lf)
{
619
	dwarf_getfuncs(&lf->cu_die, line_range_search_cb, lf, 0);
620 621 622 623
}

int find_line_range(int fd, struct line_range *lr)
{
624
	struct line_finder lf = {.lr = lr, .found = 0};
625
	int ret;
626 627 628 629 630 631 632 633
	Dwarf_Off off = 0, noff;
	size_t cuhl;
	Dwarf_Die *diep;
	Dwarf *dbg;
	int fno;

	dbg = dwarf_begin(fd, DWARF_C_READ);
	if (!dbg)
634 635
		return -ENOENT;

636
	/* Loop on CUs (Compilation Unit) */
637
	while (!lf.found) {
638 639
		ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL);
		if (ret != 0)
640 641 642
			break;

		/* Get the DIE(Debugging Information Entry) of this CU */
643 644 645
		diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die);
		if (!diep)
			continue;
646 647 648

		/* Check if target file is included. */
		if (lr->file)
649 650 651
			fno = cu_find_fileno(&lf.cu_die, lr->file);
		else
			fno = 0;
652

653
		if (!lr->file || fno) {
654 655 656
			if (lr->function)
				find_line_range_by_func(&lf);
			else {
657
				lf.fname = lr->file;
658 659
				lf.lno_s = lr->start;
				if (!lr->end)
660
					lf.lno_e = INT_MAX;
661 662 663 664 665
				else
					lf.lno_e = lr->end;
				find_line_range_by_line(&lf);
			}
		}
666
		off = noff;
667
	}
668 669
	pr_debug("path: %lx\n", (unsigned long)lr->path);
	dwarf_end(dbg);
670 671 672
	return lf.found;
}