Hook up support for userland CTF support in DTrace. This required some

modifications to libproc to support fetching the CTF info for a given file.

With this change, dtrace(1) is able to resolve type info for function and
USDT probe arguments, and function return values. In particular, the args[n]
syntax should now work for referencing arguments of userland probes,
provided that the requisite CTF info is available.

The uctf tests pass if the test programs are compiled with CTF info. The
current infrastructure around the DTrace test suite doesn't support this
yet.

Differential Revision:	https://reviews.freebsd.org/D891
MFC after:		1 month
Relnotes:		yes
Sponsored by:		EMC / Isilon Storage Division
This commit is contained in:
Mark Johnston 2014-10-03 23:20:37 +00:00
parent f24c6fe478
commit 41da933c87
9 changed files with 73 additions and 37 deletions

View File

@ -1496,6 +1496,7 @@ OLD_LIBS+=usr/lib/libpanel.so.4
OLD_LIBS+=usr/lib/libpanelw.so.4
OLD_LIBS+=usr/lib/libpmc.so.4
OLD_LIBS+=usr/lib/libproc.so.1
OLD_LIBS+=usr/lib/libproc.so.2
OLD_LIBS+=usr/lib/libradius.so.3
OLD_LIBS+=usr/lib/librpcsvc.so.4
OLD_LIBS+=usr/lib/libsdp.so.3

View File

@ -38,7 +38,7 @@ fi
./$exe &
pid=$!
$dtrace -32 -qs /dev/stdin <<EOF
$dtrace -qs /dev/stdin <<EOF
typedef struct info {
char *zi_gamename;
int zi_ndungeons;

View File

@ -434,15 +434,10 @@ static const prmap_t *
dt_pid_fix_mod(dtrace_probedesc_t *pdp, struct ps_prochandle *P)
{
char m[MAXPATHLEN];
#if defined(sun)
Lmid_t lmid = PR_LMID_EVERY;
#else
Lmid_t lmid = 0;
#endif
const char *obj;
const prmap_t *pmp;
#if defined(sun)
/*
* Pick apart the link map from the library name.
*/
@ -463,20 +458,17 @@ dt_pid_fix_mod(dtrace_probedesc_t *pdp, struct ps_prochandle *P)
} else {
obj = pdp->dtpd_mod;
}
#else
obj = pdp->dtpd_mod;
#endif
if ((pmp = Plmid_to_map(P, lmid, obj)) == NULL)
return (NULL);
#if defined(sun)
(void) Pobjname(P, pmp->pr_vaddr, m, sizeof (m));
if ((obj = strrchr(m, '/')) == NULL)
obj = &m[0];
else
obj++;
#if defined(sun)
(void) Plmid(P, pmp->pr_vaddr, &lmid);
#endif
@ -571,9 +563,7 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
{
struct ps_prochandle *P = data;
GElf_Sym sym;
#if defined(sun)
prsyminfo_t sip;
#endif
dof_helper_t dh;
GElf_Half e_type;
const char *mname;
@ -852,11 +842,7 @@ dt_pid_get_types(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp,
ctf_funcinfo_t f;
ctf_id_t argv[32];
GElf_Sym sym;
#if defined(sun)
prsyminfo_t si;
#else
void *si;
#endif
struct ps_prochandle *p;
int i, args;
char buf[DTRACE_ARGTYPELEN];
@ -941,13 +927,11 @@ dt_pid_get_types(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp,
pdp->dtpd_func, pdp->dtpd_provider, pdp->dtpd_mod);
goto out;
}
#if defined(sun)
if (ctf_func_info(fp, si.prs_id, &f) == CTF_ERR) {
dt_dprintf("failed to get ctf information for %s in %s`%s\n",
pdp->dtpd_func, pdp->dtpd_provider, pdp->dtpd_mod);
goto out;
}
#endif
(void) snprintf(buf, sizeof (buf), "%s`%s", pdp->dtpd_provider,
pdp->dtpd_mod);
@ -977,7 +961,6 @@ dt_pid_get_types(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp,
(void) ctf_type_qname(fp, f.ctc_return, adp->dtargd_native +
ret, DTRACE_ARGTYPELEN - ret, buf);
*nargs = 2;
#if defined(sun)
} else {
if (ctf_func_args(fp, si.prs_id, argc, argv) == CTF_ERR)
goto out;
@ -993,7 +976,6 @@ dt_pid_get_types(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp,
(void) ctf_type_qname(fp, argv[i], adp->dtargd_native +
ret, DTRACE_ARGTYPELEN - ret, buf);
}
#endif
}
out:
dt_proc_unlock(dtp, p);

View File

@ -38,7 +38,7 @@
#define Pxlookup_by_addr(p, a, n, s, sym, i) \
proc_addr2sym(p, a, n, s, sym)
#define Pxlookup_by_name(p, l, s1, s2, sym, a) \
proc_name2sym((p), (s1), (s2), (sym))
proc_name2sym(p, s1, s2, sym, a)
#define Paddr_to_map proc_addr2map
#define Pcreate_error strerror
#define Pdelbkpt proc_bkptdel
@ -46,10 +46,10 @@
#define Plmid(p, a, l) (-1)
#define Plmid_to_map(p, l, o) proc_obj2map((p), (o))
#define Plookup_by_addr proc_addr2sym
#define Pname_to_ctf(p, obj) NULL
#define Pname_to_ctf(p, obj) (ctf_file_t *)proc_name2ctf(p, obj)
#define Pname_to_map proc_name2map
#define Pobject_iter proc_iter_objs
#define Pobject_iter_resolved(p, f, arg) 1
#define Pobject_iter_resolved(p, f, arg) proc_iter_objs(p, f, arg)
#define Pobjname proc_objname
#define Pread proc_read
#define Prd_agent proc_rdagent

View File

@ -25,7 +25,18 @@ LDADD+= -lsupc++
DPADD+= ${LIBSTDCPLUSPLUS}
.endif
SHLIB_MAJOR= 2
.if ${MK_CDDL} != "no"
LDADD+= -lctf
DPADD+= ${LIBCTF}
IGNORE_PRAGMA= YES
CFLAGS+= -I${.CURDIR}/../../cddl/contrib/opensolaris/lib/libctf/common \
-I${.CURDIR}/../../sys/cddl/contrib/opensolaris/uts/common \
-I${.CURDIR}/../../sys/cddl/compat/opensolaris
.else
CFLAGS+= -DNO_CTF
.endif
SHLIB_MAJOR= 3
MAN=

View File

@ -37,6 +37,7 @@
#include <rtld_db.h>
#include <limits.h>
struct ctf_file;
struct proc_handle;
typedef void (*proc_child_func)(void *);
@ -67,6 +68,11 @@ typedef struct prmap {
#define MA_NOCOREDUMP 0x20
} prmap_t;
typedef struct prsyminfo {
u_int prs_lmid; /* Map id. */
u_int prs_id; /* Symbol id. */
} prsyminfo_t;
typedef int proc_map_f(void *, const prmap_t *, const char *);
typedef int proc_sym_f(void *, const GElf_Sym *, const char *);
@ -125,7 +131,9 @@ int proc_create(const char *, char * const *, proc_child_func *, void *,
struct proc_handle **);
int proc_detach(struct proc_handle *, int);
int proc_getflags(struct proc_handle *);
int proc_name2sym(struct proc_handle *, const char *, const char *, GElf_Sym *);
int proc_name2sym(struct proc_handle *, const char *, const char *,
GElf_Sym *, prsyminfo_t *);
struct ctf_file *proc_name2ctf(struct proc_handle *, const char *);
int proc_setflags(struct proc_handle *, int);
int proc_state(struct proc_handle *);
pid_t proc_getpid(struct proc_handle *);
@ -133,8 +141,7 @@ int proc_wstatus(struct proc_handle *);
int proc_getwstat(struct proc_handle *);
char * proc_signame(int, char *, size_t);
int proc_read(struct proc_handle *, void *, size_t, size_t);
const lwpstatus_t *
proc_getlwpstatus(struct proc_handle *);
const lwpstatus_t *proc_getlwpstatus(struct proc_handle *);
void proc_free(struct proc_handle *);
rd_agent_t *proc_rdagent(struct proc_handle *);
void proc_updatesyms(struct proc_handle *);

View File

@ -32,6 +32,10 @@
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#ifndef NO_CTF
#include <sys/ctf.h>
#include <sys/ctf_api.h>
#endif
#include <sys/user.h>
#include <assert.h>
@ -42,10 +46,17 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifndef NO_CTF
#include <libctf.h>
#endif
#include <libutil.h>
#include "_libproc.h"
#ifdef NO_CTF
typedef struct ctf_file ctf_file_t;
#endif
#ifndef NO_CXA_DEMANGLE
extern char *__cxa_demangle(const char *, char *, size_t *, int *);
#endif /* NO_CXA_DEMANGLE */
@ -389,7 +400,7 @@ proc_name2map(struct proc_handle *p, const char *name)
*/
static int
lookup_name(Elf *e, Elf_Scn *scn, u_long stridx, const char *symbol,
GElf_Sym *symcopy)
GElf_Sym *symcopy, prsyminfo_t *si)
{
GElf_Sym sym;
Elf_Data *data;
@ -404,6 +415,8 @@ lookup_name(Elf *e, Elf_Scn *scn, u_long stridx, const char *symbol,
s = elf_strptr(e, stridx, sym.st_name);
if (s != NULL && strcmp(s, symbol) == 0) {
memcpy(symcopy, &sym, sizeof(*symcopy));
if (si != NULL)
si->prs_id = i;
return (0);
}
}
@ -412,7 +425,7 @@ lookup_name(Elf *e, Elf_Scn *scn, u_long stridx, const char *symbol,
int
proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
GElf_Sym *symcopy)
GElf_Sym *symcopy, prsyminfo_t *si)
{
Elf *e;
Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
@ -462,11 +475,11 @@ proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
* First look up the symbol in the dynsymtab, and fall back to the
* symtab if the lookup fails.
*/
error = lookup_name(e, dynsymscn, dynsymstridx, symbol, symcopy);
error = lookup_name(e, dynsymscn, dynsymstridx, symbol, symcopy, si);
if (error == 0)
goto out;
error = lookup_name(e, symtabscn, symtabstridx, symbol, symcopy);
error = lookup_name(e, symtabscn, symtabstridx, symbol, symcopy, si);
if (error == 0)
goto out;
@ -484,6 +497,26 @@ proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
return (error);
}
ctf_file_t *
proc_name2ctf(struct proc_handle *p, const char *name)
{
#ifndef NO_CTF
prmap_t *map;
int error;
if ((map = proc_name2map(p, name)) == NULL) {
DPRINTFX("ERROR: couldn't find object %s", object);
return (NULL);
}
return (ctf_open(map->pr_mapname, &error));
#else
(void)p;
(void)name;
return (NULL);
#endif
}
int
proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
int mask, proc_sym_f *func, void *cd)

View File

@ -227,6 +227,7 @@ ATF_TC_HEAD(map_alias_name2sym, tc)
ATF_TC_BODY(map_alias_name2sym, tc)
{
GElf_Sym sym1, sym2;
prsyminfo_t si1, si2;
struct proc_handle *phdl;
int error;
@ -239,14 +240,15 @@ ATF_TC_BODY(map_alias_name2sym, tc)
* Make sure that "target_prog:main" and "a.out:main" return the same
* symbol.
*/
error = proc_name2sym(phdl, target_prog_file, "main", &sym1);
error = proc_name2sym(phdl, target_prog_file, "main", &sym1, &si1);
ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main' via %s",
target_prog_file);
error = proc_name2sym(phdl, aout_object, "main", &sym2);
error = proc_name2sym(phdl, aout_object, "main", &sym2, &si2);
ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main' via %s",
aout_object);
ATF_CHECK_EQ(memcmp(&sym1, &sym2, sizeof(sym1)), 0);
ATF_CHECK_EQ(si1.prs_id, si2.prs_id);
ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
@ -271,11 +273,11 @@ ATF_TC_BODY(symbol_lookup, tc)
phdl = start_prog(tc, false);
error = proc_name2sym(phdl, target_prog_file, "main", &main_sym);
error = proc_name2sym(phdl, target_prog_file, "main", &main_sym, NULL);
ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main'");
error = proc_name2sym(phdl, ldelf_object, "r_debug_state",
&r_debug_state_sym);
&r_debug_state_sym, NULL);
ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'r_debug_state'");
set_bkpt(phdl, r_debug_state_sym.st_value, &saved);

View File

@ -237,14 +237,14 @@ rd_reset(rd_agent_t *rdap)
GElf_Sym sym;
if (proc_name2sym(rdap->rda_php, "ld-elf.so.1", "r_debug_state",
&sym) < 0)
&sym, NULL) < 0)
return (RD_ERR);
DPRINTF("found r_debug_state at 0x%lx\n", (unsigned long)sym.st_value);
rdap->rda_preinit_addr = sym.st_value;
rdap->rda_dlactivity_addr = sym.st_value;
if (proc_name2sym(rdap->rda_php, "ld-elf.so.1", "_r_debug_postinit",
&sym) < 0)
&sym, NULL) < 0)
return (RD_ERR);
DPRINTF("found _r_debug_postinit at 0x%lx\n",
(unsigned long)sym.st_value);