コード例 #1
0
ファイル: lsdtrace.c プロジェクト: gdawg/lsdtrace
int
main(int argc, char *argv[])
{
  int c;
  probefilter_t filter;
  
  static struct option globopt[] = {
    {"provider", required_argument, NULL, 'p'},
    {"module", required_argument, NULL, 'm'},
    {"function", required_argument, NULL, 'f'},
    {"name", required_argument, NULL, 'n'},
    {NULL, 0, NULL, 0}
  };

  struct option longopts[] = {
    {"pid-probes", no_argument, &filter.pidprobes, 1},
    {NULL, 0, NULL, 0}
  };

  opterr = 0;
  memset(&filter, 0, sizeof(probefilter_t));

  while ((c = getopt_long(argc, argv, ":p:m:f:n:", globopt, NULL)) != -1){
  switch(c){
    case 'p': filter.provider = optarg; break;
    case 'm': filter.mod = optarg; break;
    case 'f': filter.func = optarg; break;
    case 'n': filter.name = optarg; break;
    default: opterr = 1; break;
  }}
  optind--;
  argv += optind;
  argc -= optind;

  optind = 0;
  while ((c = getopt_long_only(argc, argv, ":", longopts, NULL)) != -1){
  switch(c){
    case 0: break; /* set long option */
    default: opterr = 1; break;
  }}

  if (opterr)
  {
    printf(
      "usage: %s [options] [--fieldname=pattern ...]\n"
      "options:\n"
      "         \t--pid-probes\tshow pid specific probes\n"
      "filters:\n"
      , getprogname());
    for (const struct option *opt = globopt; 
          opt && opt->name; opt++)
      printf("  -%c glob\t--%s=glob\n", (char)opt->val, opt->name);
    puts("\n"
      "Lists dtrace probes. Rudimentary filtering may be applied using "
      "glob(3) pattern per field.");
    return EXIT_FAILURE;
  }

  return find_probes(&filter);
}
コード例 #2
0
ファイル: probe-finder.c プロジェクト: LittleForker/linux-2.6
/* Search function from function name */
static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
{
	struct dwarf_callback_param *param = data;
	struct probe_finder *pf = param->data;
	struct perf_probe_point *pp = &pf->pev->point;

	/* Check tag and diename */
	if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
	    !die_compare_name(sp_die, pp->function))
		return DWARF_CB_OK;

	pf->fname = dwarf_decl_file(sp_die);
	if (pp->line) { /* Function relative line */
		dwarf_decl_line(sp_die, &pf->lno);
		pf->lno += pp->line;
		param->retval = find_probe_point_by_line(pf);
	} else if (!dwarf_func_inline(sp_die)) {
		/* Real function */
		if (pp->lazy_line)
			param->retval = find_probe_point_lazy(sp_die, pf);
		else {
			if (dwarf_entrypc(sp_die, &pf->addr) != 0) {
				pr_warning("Failed to get entry address of "
					   "%s.\n", dwarf_diename(sp_die));
				param->retval = -ENOENT;
				return DWARF_CB_ABORT;
			}
			pf->addr += pp->offset;
			/* TODO: Check the address in this function */
			param->retval = call_probe_finder(sp_die, pf);
		}
	} else {
		struct dwarf_callback_param _param = {.data = (void *)pf,
						      .retval = 0};
		/* Inlined function: search instances */
		dwarf_func_inline_instances(sp_die, probe_point_inline_cb,
					    &_param);
		param->retval = _param.retval;
	}

	return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */
}

static int find_probe_point_by_func(struct probe_finder *pf)
{
	struct dwarf_callback_param _param = {.data = (void *)pf,
					      .retval = 0};
	dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0);
	return _param.retval;
}

/* Find probe points from debuginfo */
static int find_probes(int fd, struct probe_finder *pf)
{
	struct perf_probe_point *pp = &pf->pev->point;
	Dwarf_Off off, noff;
	size_t cuhl;
	Dwarf_Die *diep;
	Dwarf *dbg = NULL;
	Dwfl *dwfl;
	Dwarf_Addr bias;	/* Currently ignored */
	int ret = 0;

	dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
	if (!dbg) {
		pr_warning("No debug information found in the vmlinux - "
			"please rebuild with CONFIG_DEBUG_INFO=y.\n");
		return -EBADF;
	}

#if _ELFUTILS_PREREQ(0, 142)
	/* Get the call frame information from this dwarf */
	pf->cfi = dwarf_getcfi(dbg);
#endif

	off = 0;
	line_list__init(&pf->lcache);
	/* Loop on CUs (Compilation Unit) */
	while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
		/* Get the DIE(Debugging Information Entry) of this CU */
		diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die);
		if (!diep)
			continue;

		/* Check if target file is included. */
		if (pp->file)
			pf->fname = cu_find_realpath(&pf->cu_die, pp->file);
		else
			pf->fname = NULL;

		if (!pp->file || pf->fname) {
			if (pp->function)
				ret = find_probe_point_by_func(pf);
			else if (pp->lazy_line)
				ret = find_probe_point_lazy(NULL, pf);
			else {
				pf->lno = pp->line;
				ret = find_probe_point_by_line(pf);
			}
			if (ret < 0)
				break;
		}
		off = noff;
	}
	line_list__free(&pf->lcache);
	if (dwfl)
		dwfl_end(dwfl);

	return ret;
}

/* Add a found probe point into trace event list */
static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
{
	struct trace_event_finder *tf =
			container_of(pf, struct trace_event_finder, pf);
	struct probe_trace_event *tev;
	int ret, i;

	/* Check number of tevs */
	if (tf->ntevs == tf->max_tevs) {
		pr_warning("Too many( > %d) probe point found.\n",
			   tf->max_tevs);
		return -ERANGE;
	}
	tev = &tf->tevs[tf->ntevs++];

	ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
				     &tev->point);
	if (ret < 0)
		return ret;

	pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
		 tev->point.offset);

	/* Find each argument */
	tev->nargs = pf->pev->nargs;
	tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
	if (tev->args == NULL)
		return -ENOMEM;
	for (i = 0; i < pf->pev->nargs; i++) {
		pf->pvar = &pf->pev->args[i];
		pf->tvar = &tev->args[i];
		ret = find_variable(sp_die, pf);
		if (ret != 0)
			return ret;
	}

	return 0;
}

/* Find probe_trace_events specified by perf_probe_event from debuginfo */
int find_probe_trace_events(int fd, struct perf_probe_event *pev,
			    struct probe_trace_event **tevs, int max_tevs)
{
	struct trace_event_finder tf = {
			.pf = {.pev = pev, .callback = add_probe_trace_event},
			.max_tevs = max_tevs};
	int ret;

	/* Allocate result tevs array */
	*tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
	if (*tevs == NULL)
		return -ENOMEM;

	tf.tevs = *tevs;
	tf.ntevs = 0;

	ret = find_probes(fd, &tf.pf);
	if (ret < 0) {
		free(*tevs);
		*tevs = NULL;
		return ret;
	}

	return (ret < 0) ? ret : tf.ntevs;
}

#define MAX_VAR_LEN 64

/* Collect available variables in this scope */
static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
{
	struct available_var_finder *af = data;
	struct variable_list *vl;
	char buf[MAX_VAR_LEN];
	int tag, ret;

	vl = &af->vls[af->nvls - 1];

	tag = dwarf_tag(die_mem);
	if (tag == DW_TAG_formal_parameter ||
	    tag == DW_TAG_variable) {
		ret = convert_variable_location(die_mem, af->pf.addr,
						af->pf.fb_ops, NULL);
		if (ret == 0) {
			ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
			pr_debug2("Add new var: %s\n", buf);
			if (ret > 0)
				strlist__add(vl->vars, buf);
		}
	}

	if (af->child && dwarf_haspc(die_mem, af->pf.addr))
		return DIE_FIND_CB_CONTINUE;
	else
		return DIE_FIND_CB_SIBLING;
}

/* Add a found vars into available variables list */
static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
{
	struct available_var_finder *af =
			container_of(pf, struct available_var_finder, pf);
	struct variable_list *vl;
	Dwarf_Die die_mem, *scopes = NULL;
	int ret, nscopes;

	/* Check number of tevs */
	if (af->nvls == af->max_vls) {
		pr_warning("Too many( > %d) probe point found.\n", af->max_vls);
		return -ERANGE;
	}
	vl = &af->vls[af->nvls++];

	ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
				     &vl->point);
	if (ret < 0)
		return ret;

	pr_debug("Probe point found: %s+%lu\n", vl->point.symbol,
		 vl->point.offset);

	/* Find local variables */
	vl->vars = strlist__new(true, NULL);
	if (vl->vars == NULL)
		return -ENOMEM;
	af->child = true;
	die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem);

	/* Find external variables */
	if (!af->externs)
		goto out;
	/* Don't need to search child DIE for externs. */
	af->child = false;
	nscopes = dwarf_getscopes_die(sp_die, &scopes);
	while (nscopes-- > 1)
		die_find_child(&scopes[nscopes], collect_variables_cb,
			       (void *)af, &die_mem);
	if (scopes)
		free(scopes);

out:
	if (strlist__empty(vl->vars)) {
		strlist__delete(vl->vars);
		vl->vars = NULL;
	}

	return ret;
}

/* Find available variables at given probe point */
int find_available_vars_at(int fd, struct perf_probe_event *pev,
			   struct variable_list **vls, int max_vls,
			   bool externs)
{
	struct available_var_finder af = {
			.pf = {.pev = pev, .callback = add_available_vars},
			.max_vls = max_vls, .externs = externs};
	int ret;

	/* Allocate result vls array */
	*vls = zalloc(sizeof(struct variable_list) * max_vls);
	if (*vls == NULL)
		return -ENOMEM;

	af.vls = *vls;
	af.nvls = 0;

	ret = find_probes(fd, &af.pf);
	if (ret < 0) {
		/* Free vlist for error */
		while (af.nvls--) {
			if (af.vls[af.nvls].point.symbol)
				free(af.vls[af.nvls].point.symbol);
			if (af.vls[af.nvls].vars)
				strlist__delete(af.vls[af.nvls].vars);
		}
		free(af.vls);
		*vls = NULL;
		return ret;
	}

	return (ret < 0) ? ret : af.nvls;
}