Example #1
0
/* Get a Dwarf from offline image */
static int debuginfo__init_offline_dwarf(struct debuginfo *dbg,
					 const char *path)
{
	int fd;

	fd = open(path, O_RDONLY);
	if (fd < 0)
		return fd;

	dbg->dwfl = dwfl_begin(&offline_callbacks);
	if (!dbg->dwfl)
		goto error;

	dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd);
	if (!dbg->mod)
		goto error;

	dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias);
	if (!dbg->dbg)
		goto error;

	return 0;
error:
	if (dbg->dwfl)
		dwfl_end(dbg->dwfl);
	else
		close(fd);
	memset(dbg, 0, sizeof(*dbg));

	return -ENOENT;
}
Example #2
0
/* Get a Dwarf from live kernel image */
static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp,
					  Dwarf_Addr *bias)
{
	Dwarf *dbg;

	if (!dwflp)
		return NULL;

	*dwflp = dwfl_begin(&kernel_callbacks);
	if (!*dwflp)
		return NULL;

	/* Load the kernel dwarves: Don't care the result here */
	dwfl_linux_kernel_report_kernel(*dwflp);
	dwfl_linux_kernel_report_modules(*dwflp);

	dbg = dwfl_addrdwarf(*dwflp, addr, bias);
	/* Here, check whether we could get a real dwarf */
	if (!dbg) {
		pr_debug("Failed to find kernel dwarf at %lx\n",
			 (unsigned long)addr);
		dwfl_end(*dwflp);
		*dwflp = NULL;
	}
	return dbg;
}
static int debuginfo__init_offline_dwarf(struct debuginfo *self,
					 const char *path)
{
	Dwfl_Module *mod;
	int fd;

	fd = open(path, O_RDONLY);
	if (fd < 0)
		return fd;

	self->dwfl = dwfl_begin(&offline_callbacks);
	if (!self->dwfl)
		goto error;

	mod = dwfl_report_offline(self->dwfl, "", "", fd);
	if (!mod)
		goto error;

	self->dbg = dwfl_module_getdwarf(mod, &self->bias);
	if (!self->dbg)
		goto error;

	return 0;
error:
	if (self->dwfl)
		dwfl_end(self->dwfl);
	else
		close(fd);
	memset(self, 0, sizeof(*self));

	return -ENOENT;
}
Example #4
0
int
main (int argc, char **argv)
{
  char* args[3];
  int res = 0;
  Dwfl *dwfl;
  Dwarf_Addr bias;
  
  if (argc != 2)
    fprintf(stderr, "Usage %s <file>", argv[0]);
  
  // Pretend "dwarfsrcfiles -e <file>" was given, so we can use standard
  // dwfl argp parser to open the file for us and get our Dwfl. Useful
  // in case argument is an ET_REL file (like kernel modules). libdwfl
  // will fix up relocations for us.
  args[0] = argv[0];
  args[1] = "-e";
  args[2] = argv[1];
  
  argp_parse (dwfl_standard_argp (), 3, args, 0, NULL, &dwfl);
  
  Dwarf_Die *cu = NULL;
  while ((cu = dwfl_nextcu (dwfl, cu, &bias)) != NULL)
    res |= process_cu (cu);
  
  dwfl_end (dwfl);

  return res;
}
Example #5
0
void debuginfo__delete(struct debuginfo *dbg)
{
	if (dbg) {
		if (dbg->dwfl)
			dwfl_end(dbg->dwfl);
		free(dbg);
	}
}
void debuginfo__delete(struct debuginfo *self)
{
	if (self) {
		if (self->dwfl)
			dwfl_end(self->dwfl);
		free(self);
	}
}
Example #7
0
void
refl_end (struct refl *refl)
{
  if (refl != NULL)
    {
      dwfl_end (refl->dwfl);
    }
  free (refl);
}
Example #8
0
int
main (int argc, char *argv[])
{
  int remaining;

  /* Set locale.  */
  (void) setlocale (LC_ALL, "");

  Dwfl *dwfl = NULL;
  (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &remaining, &dwfl);
  assert (dwfl != NULL);

  int result = 0;

  /* Now handle the addresses.  In case none are given on the command
     line, read from stdin.  */
  if (remaining == argc)
    {
      /* We use no threads here which can interfere with handling a stream.  */
      (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);

      char *buf = NULL;
      size_t len = 0;
      while (!feof_unlocked (stdin))
	{
	  if (getline (&buf, &len, stdin) < 0)
	    break;

	  char *endp;
	  uintmax_t addr = strtoumax (buf, &endp, 0);
	  if (endp != buf)
	    result |= handle_address (addr, dwfl);
	  else
	    result = 1;
	}

      free (buf);
    }
  else
    {
      do
	{
	  char *endp;
	  uintmax_t addr = strtoumax (argv[remaining], &endp, 0);
	  if (endp != argv[remaining])
	    result |= handle_address (addr, dwfl);
	  else
	    result = 1;
	}
      while (++remaining < argc);
    }

  dwfl_end (dwfl);

  return result;
}
Example #9
0
File: Libdw.c Project: momiken/ghc
// Create a libdw session with DWARF information for all loaded modules
LibdwSession *libdwInit() {
    LibdwSession *session = stgCallocBytes(1, sizeof(LibdwSession),
                                           "libdwInit");
    // Initialize ELF library
    if (elf_version(EV_CURRENT) == EV_NONE) {
        sysErrorBelch("libelf version too old!");
        return NULL;
    }

    // Initialize a libdwfl session
    static char *debuginfo_path;
    static const Dwfl_Callbacks proc_callbacks =
        {
            .find_debuginfo = dwfl_standard_find_debuginfo,
            .debuginfo_path = &debuginfo_path,
            .find_elf = dwfl_linux_proc_find_elf,
        };
    session->dwfl = dwfl_begin (&proc_callbacks);
    if (session->dwfl == NULL) {
        sysErrorBelch("dwfl_begin failed: %s", dwfl_errmsg(dwfl_errno()));
        free(session);
        return NULL;
    }

    // Report the loaded modules
    int ret = dwfl_linux_proc_report(session->dwfl, getpid());
    if (ret < 0) {
        sysErrorBelch("dwfl_linux_proc_report failed: %s",
                      dwfl_errmsg(dwfl_errno()));
        goto fail;
    }
    if (dwfl_report_end (session->dwfl, NULL, NULL) != 0) {
        sysErrorBelch("dwfl_report_end failed: %s", dwfl_errmsg(dwfl_errno()));
        goto fail;
    }

    pid_t pid = getpid();
    if (! dwfl_attach_state(session->dwfl, NULL, pid, &thread_cbs, NULL)) {
        sysErrorBelch("dwfl_attach_state failed: %s",
                      dwfl_errmsg(dwfl_errno()));
        goto fail;
    }

    return session;

 fail:
    dwfl_end(session->dwfl);
    free(session);
    return NULL;
}
int
main (void)
{
  Dwfl *dwfl = dwfl_begin (&callbacks);

  for (int i = 0; i < 5; ++i)
    {
      dwfl_report_begin (dwfl);
      dwfl_report_module (dwfl, "module1", 0, 10);
      dwfl_report_end (dwfl, NULL, NULL);
    }

  dwfl_end (dwfl);

  return 0;
}
Example #11
0
int main(void)
{
	Dwfl *dw;
	Dwfl_Module *mod;
	Dwarf_Addr bias;
	Dwarf_Die *die = NULL;

	dw = dwfl_begin(&cb);
	if (!dw)
		errx(1, "dwfl_begin %s", dwfl_errmsg(-1));

	mod = dwfl_report_offline(dw, "", "tst", -1);
	if (!mod)
		errx(1, "dwfl_begin %s", dwfl_errmsg(-1));

	while ((die = dwfl_nextcu(dw, die, &bias))) {
		print_die_rec(die, -1);
		printf("\n");
	}

	dwfl_end(dw);
	return 0;
}
Example #12
0
/* Get a Dwarf from live kernel image */
static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
					       Dwarf_Addr addr)
{
	self->dwfl = dwfl_begin(&kernel_callbacks);
	if (!self->dwfl)
		return -EINVAL;

	/* Load the kernel dwarves: Don't care the result here */
	dwfl_linux_kernel_report_kernel(self->dwfl);
	dwfl_linux_kernel_report_modules(self->dwfl);

	self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias);
	/* Here, check whether we could get a real dwarf */
	if (!self->dbg) {
		pr_debug("Failed to find kernel dwarf at %lx\n",
			 (unsigned long)addr);
		dwfl_end(self->dwfl);
		memset(self, 0, sizeof(*self));
		return -ENOENT;
	}

	return 0;
}
static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
					       Dwarf_Addr addr)
{
	self->dwfl = dwfl_begin(&kernel_callbacks);
	if (!self->dwfl)
		return -EINVAL;

	
	dwfl_linux_kernel_report_kernel(self->dwfl);
	dwfl_linux_kernel_report_modules(self->dwfl);

	self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias);
	
	if (!self->dbg) {
		pr_debug("Failed to find kernel dwarf at %lx\n",
			 (unsigned long)addr);
		dwfl_end(self->dwfl);
		memset(self, 0, sizeof(*self));
		return -ENOENT;
	}

	return 0;
}
Example #14
0
void
core_handle_free(struct core_handle *ch)
{
    if (ch)
    {
        struct exe_mapping_data *seg = ch->segments, *next;
        while (seg)
        {
            free(seg->filename);

            next = seg->next;
            free(seg);
            seg = next;
        }

        if (ch->dwfl)
            dwfl_end(ch->dwfl);
        if (ch->eh)
            elf_end(ch->eh);
        if (ch->fd > 0)
            close(ch->fd);
        free(ch);
    }
}
Example #15
0
/* Get a Dwarf from offline image */
static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias)
{
	Dwfl_Module *mod;
	Dwarf *dbg = NULL;

	if (!dwflp)
		return NULL;

	*dwflp = dwfl_begin(&offline_callbacks);
	if (!*dwflp)
		return NULL;

	mod = dwfl_report_offline(*dwflp, "", "", fd);
	if (!mod)
		goto error;

	dbg = dwfl_module_getdwarf(mod, bias);
	if (!dbg) {
error:
		dwfl_end(*dwflp);
		*dwflp = NULL;
	}
	return dbg;
}
int
main (int argc, char *argv[])
{
  int remaining;

  /* Set locale.  */
  (void) setlocale (LC_ALL, "");

  struct args a = { .dwfl = NULL, .cu = NULL };

  (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &remaining,
		     &a.dwfl);
  assert (a.dwfl != NULL);
  a.argv = &argv[remaining];

  int result = 0;

  while ((a.cu = dwfl_nextcu (a.dwfl, a.cu, &a.dwbias)) != NULL)
    dwarf_getfuncs (a.cu, &handle_function, &a, 0);

  dwfl_end (a.dwfl);

  return result;
}
Example #17
0
struct core_handle *
open_coredump(const char *elf_file, const char *exe_file, char **error_msg)
{
    struct core_handle *ch = sr_mallocz(sizeof(*ch));
    struct exe_mapping_data *head = NULL, **tail = &head;

    /* Initialize libelf, open the file and get its Elf handle. */
    if (elf_version(EV_CURRENT) == EV_NONE)
    {
        set_error_elf("elf_version");
        goto fail_free;
    }

    /* Open input file, and parse it. */
    ch->fd = open(elf_file, O_RDONLY);
    if (ch->fd < 0)
    {
        set_error("Unable to open '%s': %s", elf_file, strerror(errno));
        goto fail_free;
    }

    ch->eh = elf_begin(ch->fd, ELF_C_READ_MMAP, NULL);
    if (ch->eh == NULL)
    {
        set_error_elf("elf_begin");
        goto fail_close;
    }

    /* Check that we are working with a coredump. */
    GElf_Ehdr ehdr;
    if (gelf_getehdr(ch->eh, &ehdr) == NULL || ehdr.e_type != ET_CORE)
    {
        set_error("File '%s' is not a coredump", elf_file);
        goto fail_elf;
    }

    executable_file = exe_file;
    ch->cb.find_elf = find_elf_core;
    ch->cb.find_debuginfo = find_debuginfo_none;
    ch->cb.section_address = dwfl_offline_section_address;
    ch->dwfl = dwfl_begin(&ch->cb);

#if _ELFUTILS_PREREQ(0, 158)
    if (dwfl_core_file_report(ch->dwfl, ch->eh, exe_file) == -1)
#else
    if (dwfl_core_file_report(ch->dwfl, ch->eh) == -1)
#endif
    {
        set_error_dwfl("dwfl_core_file_report");
        goto fail_dwfl;
    }

    if (dwfl_report_end(ch->dwfl, NULL, NULL) != 0)
    {
        set_error_dwfl("dwfl_report_end");
        goto fail_dwfl;
    }

    /* needed so that module filenames are available during unwinding */
    ptrdiff_t ret = dwfl_getmodules(ch->dwfl, touch_module, &tail, 0);
    if (ret == -1)
    {
        set_error_dwfl("dwfl_getmodules");
        goto fail_dwfl;
    }
    ch->segments = head;

    if (!head)
    {
        if (error_msg && !*error_msg)
            set_error("No segments found in coredump '%s'", elf_file);
        goto fail_dwfl;
    }

    return ch;

fail_dwfl:
    dwfl_end(ch->dwfl);
fail_elf:
    elf_end(ch->eh);
fail_close:
    close(ch->fd);
fail_free:
    free(ch);

    return NULL;
}
Example #18
0
int
main (int argc, char *argv[])
{
  int remaining;
  int result = 0;

  /* We use no threads here which can interfere with handling a stream.  */
  (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);

  /* Set locale.  */
  (void) setlocale (LC_ALL, "");

  /* Make sure the message catalog can be found.  */
  (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);

  /* Initialize the message catalog.  */
  (void) textdomain (PACKAGE_TARNAME);

  /* Parse and process arguments.  This includes opening the modules.  */
  argp_children[0].argp = dwfl_standard_argp ();
  argp_children[0].group = 1;
  Dwfl *dwfl = NULL;
  (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl);
  assert (dwfl != NULL);

  /* Now handle the addresses.  In case none are given on the command
     line, read from stdin.  */
  if (remaining == argc)
    {
      /* We use no threads here which can interfere with handling a stream.  */
      (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);

      char *buf = NULL;
      size_t len = 0;
      ssize_t chars;
      while (!feof_unlocked (stdin))
	{
	  if ((chars = getline (&buf, &len, stdin)) < 0)
	    break;

	  if (buf[chars - 1] == '\n')
	    buf[chars - 1] = '\0';

	  result = handle_address (buf, dwfl);
	}

      free (buf);
    }
  else
    {
      do
	result = handle_address (argv[remaining], dwfl);
      while (++remaining < argc);
    }

  dwfl_end (dwfl);

#ifdef USE_DEMANGLE
  free (demangle_buffer);
#endif

  return result;
}
Example #19
0
int coredump_make_stack_trace(int fd, const char *executable, char **ret) {

        static const Dwfl_Callbacks callbacks = {
                .find_elf = dwfl_build_id_find_elf,
                .find_debuginfo = dwfl_standard_find_debuginfo,
        };

        struct stack_context c = {};
        char *buf = NULL;
        size_t sz = 0;
        int r;

        assert(fd >= 0);
        assert(ret);

        if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
                return -errno;

        c.f = open_memstream(&buf, &sz);
        if (!c.f)
                return -ENOMEM;

        elf_version(EV_CURRENT);

        c.elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
        if (!c.elf) {
                r = -EINVAL;
                goto finish;
        }

        c.dwfl = dwfl_begin(&callbacks);
        if (!c.dwfl) {
                r = -EINVAL;
                goto finish;
        }

        if (dwfl_core_file_report(c.dwfl, c.elf, executable) < 0) {
                r = -EINVAL;
                goto finish;
        }

        if (dwfl_report_end(c.dwfl, NULL, NULL) != 0) {
                r = -EINVAL;
                goto finish;
        }

        if (dwfl_core_file_attach(c.dwfl, c.elf) < 0) {
                r = -EINVAL;
                goto finish;
        }

        if (dwfl_getthreads(c.dwfl, thread_callback, &c) < 0) {
                r = -EINVAL;
                goto finish;
        }

        c.f = safe_fclose(c.f);

        *ret = buf;
        buf = NULL;

        r = 0;

finish:
        if (c.dwfl)
                dwfl_end(c.dwfl);

        if (c.elf)
                elf_end(c.elf);

        safe_fclose(c.f);

        free(buf);

        return r;
}
Example #20
0
/* 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;
}
Example #21
0
/* Reverse search */
int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
{
	Dwarf_Die cudie, spdie, indie;
	Dwarf *dbg = NULL;
	Dwfl *dwfl = NULL;
	Dwarf_Line *line;
	Dwarf_Addr laddr, eaddr, bias = 0;
	const char *tmp;
	int lineno, ret = 0;
	bool found = false;

	/* Open the live linux kernel */
	dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
	if (!dbg) {
		pr_warning("No debug information found in the vmlinux - "
			"please rebuild with CONFIG_DEBUG_INFO=y.\n");
		ret = -EINVAL;
		goto end;
	}

	/* Adjust address with bias */
	addr += bias;
	/* Find cu die */
	if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) {
		pr_warning("Failed to find debug information for address %lx\n",
			   addr);
		ret = -EINVAL;
		goto end;
	}

	/* Find a corresponding line */
	line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr);
	if (line) {
		if (dwarf_lineaddr(line, &laddr) == 0 &&
		    (Dwarf_Addr)addr == laddr &&
		    dwarf_lineno(line, &lineno) == 0) {
			tmp = dwarf_linesrc(line, NULL, NULL);
			if (tmp) {
				ppt->line = lineno;
				ppt->file = strdup(tmp);
				if (ppt->file == NULL) {
					ret = -ENOMEM;
					goto end;
				}
				found = true;
			}
		}
	}

	/* Find a corresponding function */
	if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) {
		tmp = dwarf_diename(&spdie);
		if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0)
			goto end;

		if (ppt->line) {
			if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr,
						&indie)) {
				/* addr in an inline function */
				tmp = dwarf_diename(&indie);
				if (!tmp)
					goto end;
				ret = dwarf_decl_line(&indie, &lineno);
			} else {
				if (eaddr == addr) {	/* Function entry */
					lineno = ppt->line;
					ret = 0;
				} else
					ret = dwarf_decl_line(&spdie, &lineno);
			}
			if (ret == 0) {
				/* Make a relative line number */
				ppt->line -= lineno;
				goto found;
			}
		}
		/* We don't have a line number, let's use offset */
		ppt->offset = addr - (unsigned long)eaddr;
found:
		ppt->function = strdup(tmp);
		if (ppt->function == NULL) {
			ret = -ENOMEM;
			goto end;
		}
		found = true;
	}

end:
	if (dwfl)
		dwfl_end(dwfl);
	if (ret >= 0)
		ret = found ? 1 : 0;
	return ret;
}
Example #22
0
static int find_line_range_by_func(struct line_finder *lf)
{
	struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
	dwarf_getfuncs(&lf->cu_die, line_range_search_cb, &param, 0);
	return param.retval;
}

int find_line_range(int fd, struct line_range *lr)
{
	struct line_finder lf = {.lr = lr, .found = 0};
	int ret = 0;
	Dwarf_Off off = 0, noff;
	size_t cuhl;
	Dwarf_Die *diep;
	Dwarf *dbg = NULL;
	Dwfl *dwfl;
	Dwarf_Addr bias;	/* Currently ignored */
	const char *comp_dir;

	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;
	}

	/* Loop on CUs (Compilation Unit) */
	while (!lf.found && ret >= 0) {
		if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0)
			break;

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

		/* Check if target file is included. */
		if (lr->file)
			lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
		else
			lf.fname = 0;

		if (!lr->file || lf.fname) {
			if (lr->function)
				ret = find_line_range_by_func(&lf);
			else {
				lf.lno_s = lr->start;
				lf.lno_e = lr->end;
				ret = find_line_range_by_line(NULL, &lf);
			}
		}
		off = noff;
	}

	/* Store comp_dir */
	if (lf.found) {
		comp_dir = cu_get_comp_dir(&lf.cu_die);
		if (comp_dir) {
			lr->comp_dir = strdup(comp_dir);
			if (!lr->comp_dir)
				ret = -ENOMEM;
		}
	}

	pr_debug("path: %s\n", lr->path);
	dwfl_end(dwfl);
	return (ret < 0) ? ret : lf.found;
}
Example #23
0
File: Libdw.c Project: momiken/ghc
void libdwFree(LibdwSession *session) {
    if (session == NULL)
        return;
    dwfl_end(session->dwfl);
    stgFree(session);
}
Example #24
0
/*
 * Return:
 *	0 if return address for the program counter @pc is on stack
 *	1 if return address is in LR and no new stack frame was allocated
 *	2 if return address is in LR and a new frame was allocated (but not
 *		yet used)
 *	-1 in case of errors
 */
static int check_return_addr(struct dso *dso, u64 map_start, Dwarf_Addr pc)
{
	int		rc = -1;
	Dwfl		*dwfl;
	Dwfl_Module	*mod;
	Dwarf_Frame	*frame;
	int		ra_regno;
	Dwarf_Addr	start = pc;
	Dwarf_Addr	end = pc;
	bool		signalp;
	const char	*exec_file = dso->long_name;

	dwfl = dso->dwfl;

	if (!dwfl) {
		dwfl = dwfl_begin(&offline_callbacks);
		if (!dwfl) {
			pr_debug("dwfl_begin() failed: %s\n", dwarf_errmsg(-1));
			return -1;
		}

		mod = dwfl_report_elf(dwfl, exec_file, exec_file, -1,
						map_start, false);
		if (!mod) {
			pr_debug("dwfl_report_elf() failed %s\n",
						dwarf_errmsg(-1));
			/*
			 * We normally cache the DWARF debug info and never
			 * call dwfl_end(). But to prevent fd leak, free in
			 * case of error.
			 */
			dwfl_end(dwfl);
			goto out;
		}
		dso->dwfl = dwfl;
	}

	mod = dwfl_addrmodule(dwfl, pc);
	if (!mod) {
		pr_debug("dwfl_addrmodule() failed, %s\n", dwarf_errmsg(-1));
		goto out;
	}

	/*
	 * To work with split debug info files (eg: glibc), check both
	 * .eh_frame and .debug_frame sections of the ELF header.
	 */
	frame = get_eh_frame(mod, pc);
	if (!frame) {
		frame = get_dwarf_frame(mod, pc);
		if (!frame)
			goto out;
	}

	ra_regno = dwarf_frame_info(frame, &start, &end, &signalp);
	if (ra_regno < 0) {
		pr_debug("Return address register unavailable: %s\n",
				dwarf_errmsg(-1));
		goto out;
	}

	rc = check_return_reg(ra_regno, frame);

out:
	return rc;
}
Example #25
0
int
main (int argc, char *argv[])
{
  int cnt;

  Dwfl *dwfl = NULL;
  (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &cnt, &dwfl);
  assert (dwfl != NULL);

  Dwarf_Die *cu = NULL;
  Dwarf_Addr bias;
  do
    {
      cu = dwfl_nextcu (dwfl, cu, &bias);
      if (cu != NULL)
	{
	  Dwfl_Module *mod = dwfl_cumodule (cu);
	  const char *modname = (dwfl_module_info (mod, NULL, NULL, NULL,
						   NULL, NULL, NULL, NULL)
				 ?: "<unknown>");
	  const char *cuname = (dwarf_diename (cu) ?: "<unknown>");

	  printf ("mod: %s CU: [%" PRIx64 "] %s\n", modname,
		  dwarf_dieoffset (cu), cuname);

	  size_t lines;
	  if (dwfl_getsrclines (cu, &lines) != 0)
	    continue; // No lines...

	  for (size_t i = 0; i < lines; i++)
	    {
	      Dwfl_Line *line = dwfl_onesrcline (cu, i);

	      Dwarf_Addr addr;
	      int lineno;
	      int colno;
	      Dwarf_Word mtime;
	      Dwarf_Word length;
	      const char *src = dwfl_lineinfo (line, &addr, &lineno, &colno,
					       &mtime, &length);

	      Dwarf_Addr dw_bias;
	      Dwarf_Line *dw_line = dwfl_dwarf_line (line, &dw_bias);
	      assert (bias == dw_bias);

	      Dwarf_Addr dw_addr;
	      if (dwarf_lineaddr (dw_line, &dw_addr) != 0)
		error (EXIT_FAILURE, 0, "dwarf_lineaddr: %s",
		       dwarf_errmsg (-1));
	      assert (addr == dw_addr + dw_bias);

	      unsigned int dw_op_index;
	      if (dwarf_lineop_index (dw_line, &dw_op_index) != 0)
		error (EXIT_FAILURE, 0, "dwarf_lineop_index: %s",
		       dwarf_errmsg (-1));

	      int dw_lineno;
	      if (dwarf_lineno (dw_line, &dw_lineno) != 0)
		error (EXIT_FAILURE, 0, "dwarf_lineno: %s",
		       dwarf_errmsg (-1));
	      assert (lineno == dw_lineno);

	      int dw_colno;
	      if (dwarf_linecol (dw_line, &dw_colno) != 0)
		error (EXIT_FAILURE, 0, "dwarf_lineno: %s",
		       dwarf_errmsg (-1));
	      assert (colno == dw_colno);

	      bool begin;
	      if (dwarf_linebeginstatement (dw_line, &begin) != 0)
		error (EXIT_FAILURE, 0, "dwarf_linebeginstatement: %s",
		       dwarf_errmsg (-1));

	      bool end;
	      if (dwarf_lineendsequence (dw_line, &end) != 0)
		error (EXIT_FAILURE, 0, "dwarf_lineendsequence: %s",
		       dwarf_errmsg (-1));

	      bool pend;
	      if (dwarf_lineprologueend (dw_line, &pend) != 0)
		error (EXIT_FAILURE, 0, "dwarf_lineprologueend: %s",
		       dwarf_errmsg (-1));

	      bool ebegin;
	      if (dwarf_lineepiloguebegin (dw_line, &ebegin) != 0)
		error (EXIT_FAILURE, 0, "dwarf_lineepiloguebegin: %s",
		       dwarf_errmsg (-1));

	      bool block;
	      if (dwarf_lineblock (dw_line, &block) != 0)
		error (EXIT_FAILURE, 0, "dwarf_lineblock: %s",
		       dwarf_errmsg (-1));

	      unsigned int isa;
	      if (dwarf_lineisa (dw_line, &isa) != 0)
		error (EXIT_FAILURE, 0, "dwarf_lineisa: %s",
		       dwarf_errmsg (-1));

	      unsigned int disc;
	      if (dwarf_linediscriminator (dw_line, &disc) != 0)
		error (EXIT_FAILURE, 0, "dwarf_linediscriminator: %s",
		       dwarf_errmsg (-1));

	      const char *dw_src;
	      Dwarf_Word dw_mtime;
	      Dwarf_Word dw_length;
	      dw_src = dwarf_linesrc (dw_line, &dw_mtime, &dw_length);
	      assert (strcmp (src, dw_src) == 0);
	      assert (mtime == dw_mtime);
	      assert (length == dw_length);

	      printf ("%zd %#" PRIx64 " %s:%d:%d\n"
		      " time: %#" PRIX64 ", len: %" PRIu64
		      ", idx: %d, b: %d, e: %d"
		      ", pe: %d, eb: %d, block: %d"
		      ", isa: %d, disc: %d\n",
		      i, addr, src, lineno, colno, mtime, length,
		      dw_op_index, begin, end, pend, ebegin, block, isa, disc);

	      Dwarf_Die *linecu = dwfl_linecu (line);
	      assert (cu == linecu);

	      Dwfl_Module *linemod = dwfl_linemodule (line);
	      assert (mod == linemod);
	    }
	}
    }
  while (cu != NULL);

  dwfl_end (dwfl);

  return 0;
}