diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_sugar.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_sugar.c
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_sugar.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_sugar.c
@@ -38,12 +38,23 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/sysmacros.h>
+#include <sys/param.h>
+#include <sys/queue.h>
 
 #include <assert.h>
-#include <strings.h>
-#include <stdlib.h>
-#include <stdio.h>
 #include <ctype.h>
+#include <dwarf.h>
+#include <err.h>
+#include <fcntl.h>
+#include <gelf.h>
+#include <libdwarf.h>
+#include <libelf.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
 #include <dt_module.h>
 #include <dt_program.h>
 #include <dt_provider.h>
@@ -54,14 +65,51 @@
 #include <dt_string.h>
 #include <dt_impl.h>
 
+#include <dis_tables.h>
+
+/* kinst-related */
+struct elf_info {
+	Elf			*elf;
+	struct section	{
+		Elf_Scn		*scn;
+		GElf_Shdr	sh;
+		const char	*name;
+	}			*sl;
+	size_t			shnum;
+	int			fd;
+};
+
+struct entry {
+	const char		*callerfunc;
+	int			noff;
+	struct off {
+		const char	*func;
+		uint64_t	val;
+	}			*off;
+	TAILQ_ENTRY(entry)	next;
+};
+
 typedef struct dt_sugar_parse {
 	dtrace_hdl_t *dtsp_dtp;		/* dtrace handle */
 	dt_node_t *dtsp_pdescs;		/* probe descriptions */
 	int dtsp_num_conditions;	/* number of condition variables */
 	int dtsp_num_ifs;		/* number of "if" statements */
+	int dtsp_kinst;			/* specify if the provider is kinst */
 	dt_node_t *dtsp_clause_list;	/* list of clauses */
+	struct elf_info	dtsp_elf_kern;	/* ELF info of the kernel executable */
+	struct elf_info dtsp_elf_dbg;	/* ELF info of the kernel debug file */
+	dtrace_probedesc_t *dtsp_desc;	/* kinst pdesc to duplicate contents */
+	Dwarf_Off dtsp_dieoff;		/* DIE offset of kinst inline definition */
+	int dtsp_inline;		/* kinst probe function is inline */
+	int dtsp_entry_or_return;	/* kinst probe is entry or return */
+	TAILQ_HEAD(, entry) dtsp_head;	/* kinst inline copy entry TAILQ */
 } dt_sugar_parse_t;
 
+enum {
+	F_SUBPROGRAM,
+	F_INLINE_COPY,
+};
+
 static void dt_sugar_visit_stmts(dt_sugar_parse_t *, dt_node_t *, int);
 
 /*
@@ -186,8 +234,574 @@
 }
 
 /*
- * Visit the specified node and all of its descendants.  Currently this is only
- * used to count the number of "if" statements (dtsp_num_ifs).
+ * kinst-related
+ */
+static void
+dt_sugar_elf_init(dtrace_hdl_t *dtp, struct elf_info *ei, const char *file)
+{
+	Elf_Scn *scn;
+	GElf_Shdr sh;
+	struct section *s;
+	const char *name;
+	size_t shstrndx, ndx;
+
+	if (elf_version(EV_CURRENT) == EV_NONE)
+		errx(1, "dt_sugar: elf_version(): %s", elf_errmsg(-1));
+	if ((ei->fd = open(file, O_RDONLY)) < 0)
+		err(1, "dt_sugar: open(%s)", file);
+	if ((ei->elf = elf_begin(ei->fd, ELF_C_READ, NULL)) == NULL)
+		errx(1, "dt_sugar: elf_begin(): %s", elf_errmsg(-1));
+	if (elf_kind(ei->elf) == ELF_K_NONE)
+		errx(1, "dt_sugar: not an ELF file: %s", file);
+
+	/* Load ELF sections */
+	if (!elf_getshnum(ei->elf, &ei->shnum))
+		errx(1, "dt_sugar: elf_getshnum(): %s", elf_errmsg(-1));
+	ei->sl = dt_alloc(dtp, ei->shnum * sizeof(struct section));
+	if (ei->sl == NULL)
+		err(1, "dt_sugar: dt_alloc()");
+	if (!elf_getshstrndx(ei->elf, &shstrndx))
+		errx(1, "dt_sugar: elf_getshstrndx(): %s", elf_errmsg(-1));
+	if ((scn = elf_getscn(ei->elf, 0)) == NULL)
+		errx(1, "dt_sugar: elf_getscn(): %s", elf_errmsg(-1));
+	(void) elf_errno();
+
+	do {
+		if (gelf_getshdr(scn, &sh) == NULL) {
+			warnx("dt_sugar: gelf_getshdr(): %s", elf_errmsg(-1));
+			(void) elf_errno();
+			continue;
+		}
+		if ((name = elf_strptr(ei->elf, shstrndx, sh.sh_name)) == NULL)
+			(void) elf_errno();
+		if ((ndx = elf_ndxscn(scn)) == SHN_UNDEF && elf_errno() != 0) {
+			warnx("dt_sugar: elf_ndxscn(): %s", elf_errmsg(-1));
+			continue;
+		}
+		if (ndx >= ei->shnum)
+			continue;
+		s = &ei->sl[ndx];
+		s->scn = scn;
+		s->sh = sh;
+		s->name = name;
+	} while ((scn = elf_nextscn(ei->elf, scn)) != NULL);
+	if (elf_errno() != 0)
+		warnx("dt_sugar: elf_nextscn(): %s", elf_errmsg(-1));
+}
+
+static void
+dt_sugar_elf_deinit(dtrace_hdl_t *dtp, struct elf_info *ei)
+{
+	dt_free(dtp, ei->sl);
+	close(ei->fd);
+	elf_end(ei->elf);
+}
+
+static int
+dt_sugar_dis_get_byte(void *p)
+{
+	int ret;
+	uint8_t **instr = p;
+
+	ret = **instr;
+	(*instr)++;
+
+	return (ret);
+}
+
+/*
+ * Find the caller function and offset of an inline copy. Since we know the
+ * inline copy's boundaries (`addr_lo` and `addr_hi` arguments), the caller
+ * function is going to be the ELF symbol that the inline copy's boundaries are
+ * inside of.
+ */
+static void
+dt_sugar_kinst_find_caller_func(dt_sugar_parse_t *dp, struct off *off,
+    uint64_t addr_lo, uint64_t addr_hi)
+{
+	Elf_Data *d;
+	GElf_Sym sym;
+	struct section *s;
+	dis86_t d86;
+	uint8_t *buf;
+	uint64_t addr, lo, hi;
+	uint32_t stab;
+	int len, i, j;
+
+	/* Find the caller function's boundaries and name. */
+	off->func = NULL;
+	for (i = 1; i < dp->dtsp_elf_kern.shnum; i++) {
+		s = &dp->dtsp_elf_kern.sl[i];
+		if (s->sh.sh_type != SHT_SYMTAB && s->sh.sh_type != SHT_DYNSYM)
+			continue;
+		if (s->sh.sh_link >= dp->dtsp_elf_kern.shnum)
+			continue;
+		stab = s->sh.sh_link;
+		(void) elf_errno();
+		if ((d = elf_getdata(s->scn, NULL)) == NULL) {
+			if (elf_errno() != 0)
+				warnx("dt_sugar: elf_getdata(): %s",
+				    elf_errmsg(-1));
+			continue;
+		}
+		if (d->d_size <= 0)
+			continue;
+		if (s->sh.sh_entsize == 0)
+			continue;
+		else if (s->sh.sh_size / s->sh.sh_entsize > INT_MAX)
+			continue;
+		len = (int)(s->sh.sh_size / s->sh.sh_entsize);
+		for (j = 0; j < len; j++) {
+			if (gelf_getsym(d, j, &sym) != &sym) {
+				warnx("dt_sugar: gelf_getsym(): %s",
+				    elf_errmsg(-1));
+				continue;
+			}
+			lo = sym.st_value;
+			hi = sym.st_value + sym.st_size;
+			if (addr_lo < lo || addr_hi > hi)
+				continue;
+			if ((off->func = elf_strptr(dp->dtsp_elf_kern.elf, stab,
+			    sym.st_name)) != NULL)
+				break;
+		}
+	}
+
+	if (strcmp(dp->dtsp_desc->dtpd_name, "entry") == 0) {
+		off->val = addr_lo - lo;
+		return;
+	} else if (strcmp(dp->dtsp_desc->dtpd_name, "return") == 0)
+		;	/* nothing */
+
+	/* Find inline copy's return offset. */
+	for (i = 1; i < dp->dtsp_elf_kern.shnum; i++) {
+		s = &dp->dtsp_elf_kern.sl[i];
+		if (strcmp(s->name, ".text") != 0 ||
+		    s->sh.sh_type != SHT_PROGBITS)
+			continue;
+		(void) elf_errno();
+		if ((d = elf_getdata(s->scn, NULL)) == NULL) {
+			if (elf_errno() != 0)
+				warnx("dt_sugar: elf_getdata(): %s",
+				    elf_errmsg(-1));
+			continue;
+		}
+		if (d->d_size <= 0 || d->d_buf == NULL)
+			continue;
+
+		buf = d->d_buf;
+		addr = s->sh.sh_addr + d->d_off;
+
+		/*
+		 * Get to the inline copy's start manually to avoid potential
+		 * dtrace_disx86() failures.
+		 */
+		while (addr != addr_lo) {
+			addr++;
+			buf++;
+		}
+
+		d86.d86_data = &buf;
+		d86.d86_get_byte = dt_sugar_dis_get_byte;
+		d86.d86_check_func = NULL;
+
+		/* Get to the inline copy's end. */
+		while (addr != addr_hi) {
+			/*
+			 * XXX We might have to add #ifdefs when we port kinst
+			 * to other architectures.
+			 */
+			if (dtrace_disx86(&d86, SIZE64) != 0) {
+				warnx("dt_sugar: dtrace_disx86() failed");
+				return;
+			}
+			addr += d86.d86_len;
+		}
+		/*
+		 * DWARF considers addr_hi to be the instruction
+		 * *after* the inline copy's end, so we want to go back
+		 * one instruction.
+		 */
+		addr -= d86.d86_len;
+		off->val = addr - lo;
+		break;
+	}
+}
+
+/*
+ * Parse DWARF info recursively and create a TAILQ of entries that correspond
+ * to inline copies of the probe function.
+ */
+static void
+dt_sugar_kinst_parse_die(dt_sugar_parse_t *dp, Dwarf_Debug dbg, Dwarf_Die die,
+    int level, int flag)
+{
+	static Dwarf_Die die_root;
+	Dwarf_Die die_next;
+	Dwarf_Ranges *ranges, *rp;
+	Dwarf_Attribute attp;
+	Dwarf_Addr base0, lowpc, highpc;
+	Dwarf_Off dieoff, cuoff, culen, v_off;
+	Dwarf_Unsigned nbytes, v_udata;
+	Dwarf_Signed nranges;
+	Dwarf_Half attr, tag;
+	Dwarf_Bool v_flag;
+	Dwarf_Error error;
+	struct entry *e;
+	struct off *off;
+	char *v_str;
+	int res, noff, i, found = 0;
+
+	if (level == 0)
+		die_root = die;
+
+	if (dwarf_dieoffset(die, &dieoff, &error) != DW_DLV_OK) {
+		warnx("dt_sugar: %s", dwarf_errmsg(error));
+		goto cont;
+	}
+	if (dwarf_die_CU_offset_range(die, &cuoff, &culen, &error) != DW_DLV_OK) {
+		warnx("dt_sugar: %s", dwarf_errmsg(error));
+		cuoff = 0;
+	}
+	if (dwarf_tag(die, &tag, &error) != DW_DLV_OK) {
+		warnx("dt_sugar: %s", dwarf_errmsg(error));
+		goto cont;
+	}
+	if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
+		goto cont;
+	if (flag == F_SUBPROGRAM && tag == DW_TAG_subprogram) {
+		if (dwarf_hasattr(die, DW_AT_inline, &v_flag, &error) !=
+		    DW_DLV_OK) {
+			warnx("dt_sugar: %s", dwarf_errmsg(error));
+			goto cont;
+		}
+		if (!v_flag)
+			goto cont;
+		res = dwarf_diename(die, &v_str, &error);
+		if (res != DW_DLV_OK) {
+			warnx("dt_sugar: %s", dwarf_errmsg(error));
+			goto cont;
+		}
+		if (strcmp(v_str, dp->dtsp_desc->dtpd_func) != 0)
+			goto cont;
+		/*
+		 * The function name we're searching for has an inline
+		 * definition.
+		 */
+		found = 1;
+		goto cont;
+	} else if (flag == F_INLINE_COPY && tag == DW_TAG_inlined_subroutine) {
+		res = dwarf_attr(die, DW_AT_abstract_origin, &attp, &error);
+		if (res != DW_DLV_OK) {
+			if (res == DW_DLV_ERROR)
+				warnx("dt_sugar: %s", dwarf_errmsg(error));
+			goto cont;
+		}
+		if (dwarf_formref(attp, &v_off, &error) != DW_DLV_OK) {
+			warnx("dt_sugar: %s", dwarf_errmsg(error));
+			goto cont;
+		}
+		v_off += cuoff;
+		/* Doesn't point to the definition's DIE offset. */
+		if (v_off != dp->dtsp_dieoff)
+			goto cont;
+
+		if (dwarf_hasattr(die, DW_AT_ranges, &v_flag, &error) !=
+		    DW_DLV_OK) {
+			warnx("dt_sugar: %s", dwarf_errmsg(error));
+			goto cont;
+		}
+		if (v_flag) {
+			/* DIE has ranges */
+			res = dwarf_attr(die, DW_AT_ranges, &attp, &error);
+			if (res != DW_DLV_OK) {
+				if (res == DW_DLV_ERROR)
+					warnx("dt_sugar: %s",
+					    dwarf_errmsg(error));
+				goto cont;
+			}
+			if (dwarf_global_formref(attp, &v_off, &error) !=
+			    DW_DLV_OK) {
+				warnx("dt_sugar: %s", dwarf_errmsg(error));
+				goto cont;
+			}
+			if (dwarf_get_ranges(dbg, v_off, &ranges, &nranges,
+			    &nbytes, &error) != DW_DLV_OK) {
+				warnx("dt_sugar: %s", dwarf_errmsg(error));
+				goto cont;
+			}
+
+			res = dwarf_lowpc(die_root, &lowpc, &error);
+			if (res != DW_DLV_OK) {
+				warnx("dt_sugar: %s", dwarf_errmsg(error));
+				goto cont;
+			}
+			base0 = lowpc;
+
+			if (strcmp(dp->dtsp_desc->dtpd_name, "entry") == 0) {
+				/*
+				 * Trace the first instruction of the first
+				 * range since this is the beginning of the
+				 * inline copy.
+				 */
+				noff = 1;
+			} else if (strcmp(dp->dtsp_desc->dtpd_name, "return") == 0) {
+				/*
+				 * Trace the last instruction of every range in
+				 * case the inline copy is split into multiple
+				 * ranges (e.g if it has early `return`s).
+				 */
+				noff = nranges - 1;
+			}
+			off = dt_alloc(dp->dtsp_dtp, noff * sizeof(struct off));
+			if (off == NULL)
+				err(1, "dt_sugar: dt_alloc()");
+			for (i = 0; i < noff; i++) {
+				rp = &ranges[i];
+				if (rp->dwr_type == DW_RANGES_ADDRESS_SELECTION)
+					base0 = rp->dwr_addr2;
+				dt_sugar_kinst_find_caller_func(dp, &off[i],
+				    rp->dwr_addr1 + base0,
+				    rp->dwr_addr2 + base0);
+			}
+			dwarf_ranges_dealloc(dbg, ranges, nranges);
+		} else {
+			/* DIE has high/low PC boundaries */
+			res = dwarf_lowpc(die, &lowpc, &error);
+			if (res != DW_DLV_OK) {
+				warnx("dt_sugar: %s", dwarf_errmsg(error));
+				goto cont;
+			}
+			res = dwarf_highpc(die, &highpc, &error);
+			if (res != DW_DLV_OK) {
+				warnx("dt_sugar: %s", dwarf_errmsg(error));
+				goto cont;
+			}
+			noff = 1;
+			off = dt_alloc(dp->dtsp_dtp, noff * sizeof(struct off));
+			if (off == NULL)
+				err(1, "dt_sugar: dt_alloc()");
+			dt_sugar_kinst_find_caller_func(dp, off, lowpc,
+			    lowpc + highpc);
+		}
+	} else
+		goto cont;
+
+	e = dt_alloc(dp->dtsp_dtp, sizeof(struct entry));
+	if (e == NULL)
+		err(1, "dt_sugar: dt_alloc()");
+	e->noff = noff;
+	e->off = off;
+	TAILQ_INSERT_TAIL(&dp->dtsp_head, e, next);
+cont:
+	/*
+	 * Inline copies might appear before the declaration, so we need to
+	 * re-parse the CU.
+	 *
+	 * The rationale for choosing to re-parse the CU instead of using a
+	 * hash table of DIEs is that, because we re-parse only when an inline
+	 * definition of the function we want is found, statistically, we won't
+	 * have to re-parse many times at all considering that only a handful
+	 * of CUs will define the same function, whereas if we have used a hash
+	 * table, we would first need to parse the whole CU at once and store
+	 * all DW_TAG_inlined_subroutine DIEs (so that we can match them
+	 * afterwards). In this case, we always have to "parse" twice -- first
+	 * the CU, then the DIE table -- and also, the program would use much
+	 * more memory since we would have allocated DIEs, which most of them
+	 * would never be used.
+	 */
+	if (found) {
+		die = die_root;
+		level = 0;
+		/*
+		 * We'll be checking against the DIE offset of the definition
+		 * to determine if the inline copy's DW_AT_abstract_origin
+		 * points to it.
+		 */
+		dp->dtsp_dieoff = dieoff;
+		dp->dtsp_inline = 1;
+		flag = F_INLINE_COPY;
+	}
+
+	res = dwarf_child(die, &die_next, &error);
+	if (res == DW_DLV_ERROR)
+		warnx("dt_sugar: %s", dwarf_errmsg(error));
+	else if (res == DW_DLV_OK)
+		dt_sugar_kinst_parse_die(dp, dbg, die_next, level + 1, flag);
+
+	res = dwarf_siblingof(dbg, die, &die_next, &error);
+	if (res == DW_DLV_ERROR)
+		warnx("dt_sugar: %s", dwarf_errmsg(error));
+	else if (res == DW_DLV_OK)
+		dt_sugar_kinst_parse_die(dp, dbg, die_next, level, flag);
+
+	/*
+	 * Deallocating on level 0 will attempt to double-free, since die_root
+	 * points to the first DIE. We'll deallocate the root DIE in main().
+	 */
+	if (level > 0)
+		dwarf_dealloc(dbg, die, DW_DLA_DIE);
+}
+
+/*
+ * Append new clauses for each inline copy to the parse tree.
+ *
+ * For example, if foo() is an inline function, and bar() is an inline copy of
+ * it called from function baz() at offsets 10 and 20 respectively, we'll
+ * transform the parse tree from:
+ *
+ *	kinst::foo:<entry/return> /pred/{ acts }
+ *
+ * To:
+ *
+ *	kinst::baz:10 /pred/{ acts }
+ *	kinst::baz:20 /pred/{ acts }
+ */
+static void
+dt_sugar_kinst_create_probes(dt_sugar_parse_t *dp, dt_node_t *dnp)
+{
+	dt_node_t *pdesc, *dcopy, *dcopyhead, *p, *q;
+	struct entry *e;
+	char buf[DTRACE_FULLNAMELEN];
+	int i, j = 0;
+
+	/*
+	 * Perform a deep copy of the predicates and actions so that we can
+	 * clone them when we create new clauses for inline copies. If we don't
+	 * have a deep copy we'll end up in an infinite loop when we start
+	 * appending clauses to the clause list.
+	 */
+	p = dp->dtsp_clause_list;
+	dcopy = NULL;
+	if (p != NULL) {
+		dcopy = dt_node_xalloc(dp->dtsp_dtp, p->dn_kind);
+		if (dcopy == NULL)
+			err(1, "dt_sugar: dt_node_xalloc()");
+		dcopyhead = dcopy;
+		for (q = p; q != NULL; q = q->dn_list) {
+			dcopy->dn_pred = NULL;
+			dcopy->dn_acts = NULL;
+
+			if (q->dn_pred != NULL)
+				dcopy->dn_pred = q->dn_pred;
+			if (q->dn_acts != NULL)
+				dcopy->dn_acts = q->dn_acts;
+			if (q->dn_list != NULL) {
+				/* XXX are we leaking memory? */
+				dcopy->dn_list = dt_node_xalloc(dp->dtsp_dtp,
+				    q->dn_kind);
+				if (dcopy->dn_list == NULL)
+					err(1, "dt_sugar: dt_node_xalloc()");
+				dcopy = dcopy->dn_list;
+			}
+		}
+		dcopy = NULL;
+		dcopy = dcopyhead;
+	}
+
+	/* Clean up as well */
+	while (!TAILQ_EMPTY(&dp->dtsp_head)) {
+		e = TAILQ_FIRST(&dp->dtsp_head);
+		TAILQ_REMOVE(&dp->dtsp_head, e, next);
+		for (i = 0; i < e->noff; i++) {
+			if (j++ == 0) {
+				/*
+				 * Since we're trying to trace inline copies of
+				 * a given function by requesting a probe of
+				 * the form
+				 * `kinst::<inline_func_name>:<entry/return>`,
+				 * the requested probe, by definition cannot be
+				 * traced, and as a result DTrace will exit
+				 * with an error because it cannot create a
+				 * probe for this function. In order to get
+				 * around this, we're replacing the requested
+				 * probe's <function> and <offset> fields with
+				 * the very first inline copy's information.
+				 */
+				snprintf(buf, sizeof(buf), "%lu", e->off[i].val);
+				strcpy(dp->dtsp_desc->dtpd_func, e->off[i].func);
+				strcpy(dp->dtsp_desc->dtpd_name, buf);
+			} else {
+				/*
+				 * Create new clauses for each inline copy with
+				 * the requested probe's predicates and
+				 * actions.
+				 */
+				snprintf(buf, sizeof(buf), "%s:%s:%s:%lu",
+				    dp->dtsp_desc->dtpd_provider,
+				    dp->dtsp_desc->dtpd_mod,
+				    e->off[i].func, e->off[i].val);
+				pdesc = dt_node_pdesc_by_name(strdup(buf));
+
+				/* Clone all predicates and actions. */
+				for (p = dcopy; p != NULL; p = p->dn_list) {
+					dt_sugar_append_clause(dp,
+					    dt_node_clause(pdesc,
+					    p->dn_pred, p->dn_acts));
+				}
+			}
+		}
+		dt_free(dp->dtsp_dtp, e->off);
+		dt_free(dp->dtsp_dtp, e);
+	}
+}
+
+/*
+ * Initialize libelf and libdwarf and parse kernel.debug's DWARF info.
+ */
+static void
+dt_sugar_do_kinst_inline(dt_sugar_parse_t *dp, dt_node_t *dnp)
+{
+	Dwarf_Debug dbg;
+	Dwarf_Die die;
+	Dwarf_Error error;
+	char dbgfile[MAXPATHLEN];
+	int res = DW_DLV_OK;
+
+	/* We only make entry and return probes for inline functions. */
+	if (strcmp(dp->dtsp_desc->dtpd_name, "entry") != 0 &&
+	    strcmp(dp->dtsp_desc->dtpd_name, "return") != 0)
+		return;
+
+	(void) snprintf(dbgfile, sizeof(dbgfile), "/usr/lib/debug/%s.debug",
+	    dp->dtsp_dtp->bootfile);
+	dt_sugar_elf_init(dp->dtsp_dtp, &dp->dtsp_elf_kern,
+	    dp->dtsp_dtp->bootfile);
+	dt_sugar_elf_init(dp->dtsp_dtp, &dp->dtsp_elf_dbg, dbgfile);
+
+	if (dwarf_elf_init(dp->dtsp_elf_dbg.elf, DW_DLC_READ, NULL, NULL, &dbg,
+	    &error) != DW_DLV_OK)
+		errx(1, "dt_sugar: dwarf_elf_init(): %s", dwarf_errmsg(error));
+
+	dp->dtsp_entry_or_return = 1;
+
+	TAILQ_INIT(&dp->dtsp_head);
+	/*
+	 * Parse DWARF info for kernel.debug and create entries for the inline
+	 * copies we'll create probes for.
+	 */
+	do {
+		while ((res = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL,
+		    NULL, &error)) == DW_DLV_OK) {
+			die = NULL;
+			while (dwarf_siblingof(dbg, die, &die, &error) ==
+			    DW_DLV_OK) {
+				dt_sugar_kinst_parse_die(dp, dbg, die, 0,
+				    F_SUBPROGRAM);
+			}
+			dwarf_dealloc(dbg, die, DW_DLA_DIE);
+		}
+		if (res == DW_DLV_ERROR)
+			warnx("dt_sugar: %s", dwarf_errmsg(error));
+	} while (dwarf_next_types_section(dbg, &error) == DW_DLV_OK);
+
+	dt_sugar_elf_deinit(dp->dtsp_dtp, &dp->dtsp_elf_kern);
+	dt_sugar_elf_deinit(dp->dtsp_dtp, &dp->dtsp_elf_dbg);
+	dwarf_finish(dbg, &error);
+}
+
+/*
+ * Visit the specified node and all of its descendants.
  */
 static void
 dt_sugar_visit_all(dt_sugar_parse_t *dp, dt_node_t *dnp)
@@ -201,7 +815,18 @@
 	case DT_NODE_SYM:
 	case DT_NODE_TYPE:
 	case DT_NODE_PROBE:
+		break;
+
 	case DT_NODE_PDESC:
+		if (strcmp(dnp->dn_desc->dtpd_provider, "kinst") != 0)
+			break;
+		dp->dtsp_kinst = 1;
+		dp->dtsp_inline = 0;
+		dp->dtsp_entry_or_return = 0;
+		dp->dtsp_desc = dnp->dn_desc;
+		dt_sugar_do_kinst_inline(dp, dnp);
+		break;
+
 	case DT_NODE_IDENT:
 		break;
 
@@ -507,10 +1132,25 @@
 		    dt_sugar_new_clearerror_clause(&dp));
 	}
 
+	if (dp.dtsp_kinst) {
+		if (dp.dtsp_inline)
+			dt_sugar_kinst_create_probes(&dp, clause);
+		else if (!dp.dtsp_inline && dp.dtsp_entry_or_return) {
+			/*
+			 * Delegate non-inline function probes to FBT so that
+			 * we don't duplicate FBT code in kinst.
+			 */
+			strlcpy(dp.dtsp_desc->dtpd_provider, "fbt",
+			    sizeof(dp.dtsp_desc->dtpd_provider));
+		}
+		/* Regular kinst probes are not affected. */
+	}
+
 	if (dp.dtsp_clause_list != NULL &&
 	    dp.dtsp_clause_list->dn_list != NULL && !dtp->dt_has_sugar) {
 		dtp->dt_has_sugar = B_TRUE;
 		dt_sugar_prepend_clause(&dp, dt_sugar_makeerrorclause());
 	}
+
 	return (dp.dtsp_clause_list);
 }
diff --git a/cddl/lib/libdtrace/Makefile b/cddl/lib/libdtrace/Makefile
--- a/cddl/lib/libdtrace/Makefile
+++ b/cddl/lib/libdtrace/Makefile
@@ -128,7 +128,7 @@
 
 YFLAGS+=-d
 
-LIBADD=	ctf elf proc pthread rtld_db
+LIBADD=	ctf dwarf elf proc pthread rtld_db
 
 CLEANFILES=	dt_errtags.c dt_names.c
 
diff --git a/share/man/man4/dtrace_kinst.4 b/share/man/man4/dtrace_kinst.4
--- a/share/man/man4/dtrace_kinst.4
+++ b/share/man/man4/dtrace_kinst.4
@@ -36,9 +36,22 @@
 The DTrace
 .Nm kinst
 provider allows the user to trace any instruction in a given kernel function.
-<function> corresponds to the function to be traced, and <instruction> is the
-offset to the specific instruction, and can be obtained from the function's
-disassembly using kgdb from the gdb package.
+.Cm <function>
+corresponds to the function to be traced, and
+.Cm <instruction>
+is the offset to the specific instruction, and can be obtained from the
+function's disassembly using kgdb from the gdb package.
+.Pp
+.Nm kinst
+can also trace inline functions by requesting a probe of the form
+.Cm kinst::<inline_func>:<entry/return> .
+If the probe is
+.Cm entry
+or
+.Cm return
+but the function is not an inline one, the probe will be delegated to FBT,
+otherwise DTrace will find all call sites of the inline function and create
+individual probes for each one of them.
 .Pp
 .Nm kinst
 creates probes on-demand, meaning it searches for and parses the function's
@@ -72,13 +85,39 @@
   2  81500                       vm_fault:4 0x1fab9bef0000
   2  81500                       vm_fault:4 0xe16cf749000
   0  81500                       vm_fault:4 0x13587c366000
-  ...
+  ^C
 .Ed
 .Pp
 Trace all instructions in
 .Fn amd64_syscall :
 .Bd -literal -offset indent
 # dtrace -n 'kinst::amd64_syscall:'
+dtrace: description 'kinst::amd64_syscall:' matched 458 probes
+CPU     ID                    FUNCTION:NAME
+  2  80676                amd64_syscall:323
+  2  80677                amd64_syscall:326
+  2  80678                amd64_syscall:334
+  2  80679                amd64_syscall:339
+  2  80680                amd64_syscall:345
+  2  80681                amd64_syscall:353
+  ^C
+.Ed
+.Pp
+Trace the return point of
+.Fn vm_page_mvqueue ,
+which is an inline function:
+.Bd -literal -offset indent
+# dtrace -n 'kinst::vm_page_mvqueue:return'
+dtrace: description 'kinst::vm_page_mvqueue:return' matched 15 probes
+CPU     ID                    FUNCTION:NAME
+  2  80627               vm_page_advise:421
+  2  80627               vm_page_advise:421
+  2  80627               vm_page_advise:421
+  2  80618            vm_page_deactivate:85
+  1  80618            vm_page_deactivate:85
+  2  80618            vm_page_deactivate:85
+  1  80618            vm_page_deactivate:85
+  ^C
 .Ed
 .Sh SEE ALSO
 .Xr dtrace 1
diff --git a/share/mk/src.libnames.mk b/share/mk/src.libnames.mk
--- a/share/mk/src.libnames.mk
+++ b/share/mk/src.libnames.mk
@@ -384,7 +384,7 @@
 _DP_vmmapi=	util
 _DP_opencsd=	cxxrt
 _DP_ctf=	spl z
-_DP_dtrace=	ctf elf proc pthread rtld_db
+_DP_dtrace=	ctf dwarf elf proc pthread rtld_db
 _DP_xo=		util
 _DP_ztest=	geom m nvpair umem zpool pthread avl zfs_core spl zutil zfs uutil icp
 # The libc dependencies are not strictly needed but are defined to make the