]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/dev/dtrace/dtrace.c
xnu-6153.11.26.tar.gz
[apple/xnu.git] / bsd / dev / dtrace / dtrace.c
index a83adc712e2dc1f68406b6c4b38320652afa2572..9cc3b6094762fd468df658ceb333d3aba4bc458f 100644 (file)
@@ -29,8 +29,6 @@
  * Use is subject to license terms.
  */
 
-/* #pragma ident       "@(#)dtrace.c   1.65    08/07/02 SMI" */
-
 /*
  * DTrace - Dynamic Tracing for Solaris
  *
@@ -75,6 +73,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/conf.h>
+#include <sys/random.h>
 #include <sys/systm.h>
 #include <sys/dtrace_impl.h>
 #include <sys/param.h>
 #include <machine/monotonic.h>
 #endif /* MONOTONIC */
 
+#include "dtrace_xoroshiro128_plus.h"
+
 #include <IOKit/IOPlatformExpert.h>
 
 #include <kern/cpu_data.h>
@@ -112,6 +113,7 @@ extern uint32_t pmap_find_phys(void *, uint64_t);
 extern boolean_t pmap_valid_page(uint32_t);
 extern void OSKextRegisterKextsWithDTrace(void);
 extern kmod_info_t g_kernel_kmod_info;
+extern void commpage_update_dof(boolean_t enabled);
 
 /* Solaris proc_t is the struct. Darwin's proc_t is a pointer to it. */
 #define proc_t struct proc /* Steer clear of the Darwin typedef for proc_t */
@@ -182,12 +184,12 @@ dtrace_optval_t dtrace_jstackstrsize_default = 512;
 dtrace_optval_t dtrace_buflimit_default = 75;
 dtrace_optval_t dtrace_buflimit_min = 1;
 dtrace_optval_t dtrace_buflimit_max = 99;
+size_t         dtrace_nprobes_default = 4;
 int            dtrace_msgdsize_max = 128;
 hrtime_t       dtrace_chill_max = 500 * (NANOSEC / MILLISEC);  /* 500 ms */
 hrtime_t       dtrace_chill_interval = NANOSEC;                /* 1000 ms */
 int            dtrace_devdepth_max = 32;
 int            dtrace_err_verbose;
-int            dtrace_provide_private_probes = 0;
 hrtime_t       dtrace_deadman_interval = NANOSEC;
 hrtime_t       dtrace_deadman_timeout = (hrtime_t)10 * NANOSEC;
 hrtime_t       dtrace_deadman_user = (hrtime_t)30 * NANOSEC;
@@ -323,26 +325,60 @@ static dtrace_pattr_t     dtrace_provider_attr = {
 };
 
 static void
-dtrace_nullop(void)
-{}
+dtrace_provide_nullop(void *arg, const dtrace_probedesc_t *desc)
+{
+#pragma unused(arg, desc)
+}
+
+static void
+dtrace_provide_module_nullop(void *arg, struct modctl *ctl)
+{
+#pragma unused(arg, ctl)
+}
 
 static int
-dtrace_enable_nullop(void)
+dtrace_enable_nullop(void *arg, dtrace_id_t id, void *parg)
 {
+#pragma unused(arg, id, parg)
     return (0);
 }
 
+static void
+dtrace_disable_nullop(void *arg, dtrace_id_t id, void *parg)
+{
+#pragma unused(arg, id, parg)
+}
+
+static void
+dtrace_suspend_nullop(void *arg, dtrace_id_t id, void *parg)
+{
+#pragma unused(arg, id, parg)
+}
+
+static void
+dtrace_resume_nullop(void *arg, dtrace_id_t id, void *parg)
+{
+#pragma unused(arg, id, parg)
+}
+
+static void
+dtrace_destroy_nullop(void *arg, dtrace_id_t id, void *parg)
+{
+#pragma unused(arg, id, parg)
+}
+
+
 static dtrace_pops_t dtrace_provider_ops = {
-       .dtps_provide = (void (*)(void *, const dtrace_probedesc_t *))dtrace_nullop,
-       .dtps_provide_module =  (void (*)(void *, struct modctl *))dtrace_nullop,
-       .dtps_enable =  (int (*)(void *, dtrace_id_t, void *))dtrace_nullop,
-       .dtps_disable = (void (*)(void *, dtrace_id_t, void *))dtrace_nullop,
-       .dtps_suspend = (void (*)(void *, dtrace_id_t, void *))dtrace_nullop,
-       .dtps_resume =  (void (*)(void *, dtrace_id_t, void *))dtrace_nullop,
+       .dtps_provide = dtrace_provide_nullop,
+       .dtps_provide_module =  dtrace_provide_module_nullop,
+       .dtps_enable =  dtrace_enable_nullop,
+       .dtps_disable = dtrace_disable_nullop,
+       .dtps_suspend = dtrace_suspend_nullop,
+       .dtps_resume =  dtrace_resume_nullop,
        .dtps_getargdesc =      NULL,
        .dtps_getargval =       NULL,
        .dtps_usermode =        NULL,
-       .dtps_destroy = (void (*)(void *, dtrace_id_t, void *))dtrace_nullop,
+       .dtps_destroy = dtrace_destroy_nullop,
 };
 
 static dtrace_id_t     dtrace_probeid_begin;   /* special BEGIN probe */
@@ -550,7 +586,7 @@ dtrace_load##bits(uintptr_t addr)                                   \
        {                                                               \
        volatile vm_offset_t recover = (vm_offset_t)&&dtraceLoadRecover##bits;          \
        *flags |= CPU_DTRACE_NOFAULT;                                   \
-       recover = dtrace_set_thread_recover(current_thread(), recover); \
+       recover = dtrace_sign_and_set_thread_recover(current_thread(), recover);        \
        /*CSTYLED*/                                                     \
        /*                                                              \
        * PR6394061 - avoid device memory that is unpredictably         \
@@ -821,46 +857,16 @@ SYSCTL_PROC(_kern_dtrace, OID_AUTO, global_maxsize,
        &dtrace_statvar_maxsize, 0,
        sysctl_dtrace_statvar_maxsize, "Q", "dtrace statvar maxsize");
 
-static int
-sysctl_dtrace_provide_private_probes SYSCTL_HANDLER_ARGS
-{
-#pragma unused(oidp, arg2)
-       int error;
-       int value = *(int *) arg1;
-
-       error = sysctl_io_number(req, value, sizeof(value), &value, NULL);
-       if (error)
-               return (error);
-
-       if (req->newptr) {
-               if (value != 0 && value != 1)
-                       return (ERANGE);
-
-               /*
-                * We do not allow changing this back to zero, as private probes
-                * would still be left registered
-                */
-               if (value != 1)
-                       return (EPERM);
-
-               lck_mtx_lock(&dtrace_lock);
-               dtrace_provide_private_probes = value;
-               lck_mtx_unlock(&dtrace_lock);
-       }
-       return (0);
-}
 
 /*
  * kern.dtrace.provide_private_probes
  *
  * Set whether the providers must provide the private probes.  This is
- * mainly used by the FBT provider to request probes for the private/static
- * symbols.
+ * kept as compatibility as they are always provided.
  */
-SYSCTL_PROC(_kern_dtrace, OID_AUTO, provide_private_probes,
-       CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
-       &dtrace_provide_private_probes, 0,
-       sysctl_dtrace_provide_private_probes, "I", "provider must provide the private probes");
+SYSCTL_INT(_kern_dtrace, OID_AUTO, provide_private_probes,
+       CTLFLAG_RD | CTLFLAG_LOCKED,
+       (int *)NULL, 1, "provider must provide the private probes");
 
 /*
  * kern.dtrace.dof_mode
@@ -1259,11 +1265,72 @@ dtrace_vcanload(void *src, dtrace_diftype_t *type, size_t *remain,
                vstate));
 }
 
+#define        isdigit(ch)     ((ch) >= '0' && (ch) <= '9')
+#define        islower(ch)     ((ch) >= 'a' && (ch) <= 'z')
+#define        isspace(ch)     (((ch) == ' ') || ((ch) == '\r') || ((ch) == '\n') || \
+                       ((ch) == '\t') || ((ch) == '\f'))
+#define        isxdigit(ch)    (isdigit(ch) || ((ch) >= 'a' && (ch) <= 'f') || \
+                       ((ch) >= 'A' && (ch) <= 'F'))
+#define        lisalnum(x)     \
+       (isdigit(x) || ((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z'))
+
+#define        DIGIT(x)        \
+       (isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
+
+/*
+ * Convert a string to a signed integer using safe loads.
+ */
+static int64_t
+dtrace_strtoll(char *input, int base, size_t limit)
+{
+       uintptr_t pos = (uintptr_t)input;
+       int64_t val = 0;
+       int x;
+       boolean_t neg = B_FALSE;
+       char c, cc, ccc;
+       uintptr_t end = pos + limit;
+
+       /*
+        * Consume any whitespace preceding digits.
+        */
+       while ((c = dtrace_load8(pos)) == ' ' || c == '\t')
+               pos++;
+
+       /*
+        * Handle an explicit sign if one is present.
+        */
+       if (c == '-' || c == '+') {
+               if (c == '-')
+                       neg = B_TRUE;
+               c = dtrace_load8(++pos);
+       }
+
+       /*
+        * Check for an explicit hexadecimal prefix ("0x" or "0X") and skip it
+        * if present.
+        */
+       if (base == 16 && c == '0' && ((cc = dtrace_load8(pos + 1)) == 'x' ||
+           cc == 'X') && isxdigit(ccc = dtrace_load8(pos + 2))) {
+               pos += 2;
+               c = ccc;
+       }
+
+       /*
+        * Read in contiguous digits until the first non-digit character.
+        */
+       for (; pos < end && c != '\0' && lisalnum(c) && (x = DIGIT(c)) < base;
+           c = dtrace_load8(++pos))
+               val = val * base + x;
+
+       return (neg ? -val : val);
+}
+
+
 /*
  * Compare two strings using safe loads.
  */
 static int
-dtrace_strncmp(char *s1, char *s2, size_t limit)
+dtrace_strncmp(const char *s1, const char *s2, size_t limit)
 {
        uint8_t c1, c2;
        volatile uint16_t *flags;
@@ -3239,10 +3306,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
                ASSERT(mstate->dtms_present & DTRACE_MSTATE_ARGS);
                if (ndx >= sizeof (mstate->dtms_arg) /
                    sizeof (mstate->dtms_arg[0])) {
-                       /*
-                        * APPLE NOTE: Account for introduction of __dtrace_probe()
-                        */
-                       int aframes = mstate->dtms_probe->dtpr_aframes + 3;
+                       int aframes = mstate->dtms_probe->dtpr_aframes + 2;
                        dtrace_vstate_t *vstate = &state->dts_vstate;
                        dtrace_provider_t *pv;
                        uint64_t val;
@@ -3348,10 +3412,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
                if (!dtrace_priv_kernel(state))
                        return (0);
                if (!(mstate->dtms_present & DTRACE_MSTATE_STACKDEPTH)) {
-                       /*
-                        * APPLE NOTE: Account for introduction of __dtrace_probe()
-                        */
-                       int aframes = mstate->dtms_probe->dtpr_aframes + 3;
+                       int aframes = mstate->dtms_probe->dtpr_aframes + 2;
 
                        mstate->dtms_stackdepth = dtrace_getstackdepth(aframes);
                        mstate->dtms_present |= DTRACE_MSTATE_STACKDEPTH;
@@ -3382,10 +3443,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
                if (!dtrace_priv_kernel(state))
                        return (0);
                if (!(mstate->dtms_present & DTRACE_MSTATE_CALLER)) {
-                       /*
-                        * APPLE NOTE: Account for introduction of __dtrace_probe()
-                        */
-                       int aframes = mstate->dtms_probe->dtpr_aframes + 3;
+                       int aframes = mstate->dtms_probe->dtpr_aframes + 2;
 
                        if (!DTRACE_ANCHORED(mstate->dtms_probe)) {
                                /*
@@ -3629,6 +3687,458 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
        }
 }
 
+typedef enum dtrace_json_state {
+       DTRACE_JSON_REST = 1,
+       DTRACE_JSON_OBJECT,
+       DTRACE_JSON_STRING,
+       DTRACE_JSON_STRING_ESCAPE,
+       DTRACE_JSON_STRING_ESCAPE_UNICODE,
+       DTRACE_JSON_COLON,
+       DTRACE_JSON_COMMA,
+       DTRACE_JSON_VALUE,
+       DTRACE_JSON_IDENTIFIER,
+       DTRACE_JSON_NUMBER,
+       DTRACE_JSON_NUMBER_FRAC,
+       DTRACE_JSON_NUMBER_EXP,
+       DTRACE_JSON_COLLECT_OBJECT
+} dtrace_json_state_t;
+
+/*
+ * This function possesses just enough knowledge about JSON to extract a single
+ * value from a JSON string and store it in the scratch buffer.  It is able
+ * to extract nested object values, and members of arrays by index.
+ *
+ * elemlist is a list of JSON keys, stored as packed NUL-terminated strings, to
+ * be looked up as we descend into the object tree.  e.g.
+ *
+ *    foo[0].bar.baz[32] --> "foo" NUL "0" NUL "bar" NUL "baz" NUL "32" NUL
+ *       with nelems = 5.
+ *
+ * The run time of this function must be bounded above by strsize to limit the
+ * amount of work done in probe context.  As such, it is implemented as a
+ * simple state machine, reading one character at a time using safe loads
+ * until we find the requested element, hit a parsing error or run off the
+ * end of the object or string.
+ *
+ * As there is no way for a subroutine to return an error without interrupting
+ * clause execution, we simply return NULL in the event of a missing key or any
+ * other error condition.  Each NULL return in this function is commented with
+ * the error condition it represents -- parsing or otherwise.
+ *
+ * The set of states for the state machine closely matches the JSON
+ * specification (http://json.org/).  Briefly:
+ *
+ *   DTRACE_JSON_REST:
+ *     Skip whitespace until we find either a top-level Object, moving
+ *     to DTRACE_JSON_OBJECT; or an Array, moving to DTRACE_JSON_VALUE.
+ *
+ *   DTRACE_JSON_OBJECT:
+ *     Locate the next key String in an Object.  Sets a flag to denote
+ *     the next String as a key string and moves to DTRACE_JSON_STRING.
+ *
+ *   DTRACE_JSON_COLON:
+ *     Skip whitespace until we find the colon that separates key Strings
+ *     from their values.  Once found, move to DTRACE_JSON_VALUE.
+ *
+ *   DTRACE_JSON_VALUE:
+ *     Detects the type of the next value (String, Number, Identifier, Object
+ *     or Array) and routes to the states that process that type.  Here we also
+ *     deal with the element selector list if we are requested to traverse down
+ *     into the object tree.
+ *
+ *   DTRACE_JSON_COMMA:
+ *     Skip whitespace until we find the comma that separates key-value pairs
+ *     in Objects (returning to DTRACE_JSON_OBJECT) or values in Arrays
+ *     (similarly DTRACE_JSON_VALUE).  All following literal value processing
+ *     states return to this state at the end of their value, unless otherwise
+ *     noted.
+ *
+ *   DTRACE_JSON_NUMBER, DTRACE_JSON_NUMBER_FRAC, DTRACE_JSON_NUMBER_EXP:
+ *     Processes a Number literal from the JSON, including any exponent
+ *     component that may be present.  Numbers are returned as strings, which
+ *     may be passed to strtoll() if an integer is required.
+ *
+ *   DTRACE_JSON_IDENTIFIER:
+ *     Processes a "true", "false" or "null" literal in the JSON.
+ *
+ *   DTRACE_JSON_STRING, DTRACE_JSON_STRING_ESCAPE,
+ *   DTRACE_JSON_STRING_ESCAPE_UNICODE:
+ *     Processes a String literal from the JSON, whether the String denotes
+ *     a key, a value or part of a larger Object.  Handles all escape sequences
+ *     present in the specification, including four-digit unicode characters,
+ *     but merely includes the escape sequence without converting it to the
+ *     actual escaped character.  If the String is flagged as a key, we
+ *     move to DTRACE_JSON_COLON rather than DTRACE_JSON_COMMA.
+ *
+ *   DTRACE_JSON_COLLECT_OBJECT:
+ *     This state collects an entire Object (or Array), correctly handling
+ *     embedded strings.  If the full element selector list matches this nested
+ *     object, we return the Object in full as a string.  If not, we use this
+ *     state to skip to the next value at this level and continue processing.
+ */
+static char *
+dtrace_json(uint64_t size, uintptr_t json, char *elemlist, int nelems,
+    char *dest)
+{
+       dtrace_json_state_t state = DTRACE_JSON_REST;
+       int64_t array_elem = INT64_MIN;
+       int64_t array_pos = 0;
+       uint8_t escape_unicount = 0;
+       boolean_t string_is_key = B_FALSE;
+       boolean_t collect_object = B_FALSE;
+       boolean_t found_key = B_FALSE;
+       boolean_t in_array = B_FALSE;
+       uint32_t braces = 0, brackets = 0;
+       char *elem = elemlist;
+       char *dd = dest;
+       uintptr_t cur;
+
+       for (cur = json; cur < json + size; cur++) {
+               char cc = dtrace_load8(cur);
+               if (cc == '\0')
+                       return (NULL);
+
+               switch (state) {
+               case DTRACE_JSON_REST:
+                       if (isspace(cc))
+                               break;
+
+                       if (cc == '{') {
+                               state = DTRACE_JSON_OBJECT;
+                               break;
+                       }
+
+                       if (cc == '[') {
+                               in_array = B_TRUE;
+                               array_pos = 0;
+                               array_elem = dtrace_strtoll(elem, 10, size);
+                               found_key = array_elem == 0 ? B_TRUE : B_FALSE;
+                               state = DTRACE_JSON_VALUE;
+                               break;
+                       }
+
+                       /*
+                        * ERROR: expected to find a top-level object or array.
+                        */
+                       return (NULL);
+               case DTRACE_JSON_OBJECT:
+                       if (isspace(cc))
+                               break;
+
+                       if (cc == '"') {
+                               state = DTRACE_JSON_STRING;
+                               string_is_key = B_TRUE;
+                               break;
+                       }
+
+                       /*
+                        * ERROR: either the object did not start with a key
+                        * string, or we've run off the end of the object
+                        * without finding the requested key.
+                        */
+                       return (NULL);
+               case DTRACE_JSON_STRING:
+                       if (cc == '\\') {
+                               *dd++ = '\\';
+                               state = DTRACE_JSON_STRING_ESCAPE;
+                               break;
+                       }
+
+                       if (cc == '"') {
+                               if (collect_object) {
+                                       /*
+                                        * We don't reset the dest here, as
+                                        * the string is part of a larger
+                                        * object being collected.
+                                        */
+                                       *dd++ = cc;
+                                       collect_object = B_FALSE;
+                                       state = DTRACE_JSON_COLLECT_OBJECT;
+                                       break;
+                               }
+                               *dd = '\0';
+                               dd = dest; /* reset string buffer */
+                               if (string_is_key) {
+                                       if (dtrace_strncmp(dest, elem,
+                                           size) == 0)
+                                               found_key = B_TRUE;
+                               } else if (found_key) {
+                                       if (nelems > 1) {
+                                               /*
+                                                * We expected an object, not
+                                                * this string.
+                                                */
+                                               return (NULL);
+                                       }
+                                       return (dest);
+                               }
+                               state = string_is_key ? DTRACE_JSON_COLON :
+                                   DTRACE_JSON_COMMA;
+                               string_is_key = B_FALSE;
+                               break;
+                       }
+
+                       *dd++ = cc;
+                       break;
+               case DTRACE_JSON_STRING_ESCAPE:
+                       *dd++ = cc;
+                       if (cc == 'u') {
+                               escape_unicount = 0;
+                               state = DTRACE_JSON_STRING_ESCAPE_UNICODE;
+                       } else {
+                               state = DTRACE_JSON_STRING;
+                       }
+                       break;
+               case DTRACE_JSON_STRING_ESCAPE_UNICODE:
+                       if (!isxdigit(cc)) {
+                               /*
+                                * ERROR: invalid unicode escape, expected
+                                * four valid hexidecimal digits.
+                                */
+                               return (NULL);
+                       }
+
+                       *dd++ = cc;
+                       if (++escape_unicount == 4)
+                               state = DTRACE_JSON_STRING;
+                       break;
+               case DTRACE_JSON_COLON:
+                       if (isspace(cc))
+                               break;
+
+                       if (cc == ':') {
+                               state = DTRACE_JSON_VALUE;
+                               break;
+                       }
+
+                       /*
+                        * ERROR: expected a colon.
+                        */
+                       return (NULL);
+               case DTRACE_JSON_COMMA:
+                       if (isspace(cc))
+                               break;
+
+                       if (cc == ',') {
+                               if (in_array) {
+                                       state = DTRACE_JSON_VALUE;
+                                       if (++array_pos == array_elem)
+                                               found_key = B_TRUE;
+                               } else {
+                                       state = DTRACE_JSON_OBJECT;
+                               }
+                               break;
+                       }
+
+                       /*
+                        * ERROR: either we hit an unexpected character, or
+                        * we reached the end of the object or array without
+                        * finding the requested key.
+                        */
+                       return (NULL);
+               case DTRACE_JSON_IDENTIFIER:
+                       if (islower(cc)) {
+                               *dd++ = cc;
+                               break;
+                       }
+
+                       *dd = '\0';
+                       dd = dest; /* reset string buffer */
+
+                       if (dtrace_strncmp(dest, "true", 5) == 0 ||
+                           dtrace_strncmp(dest, "false", 6) == 0 ||
+                           dtrace_strncmp(dest, "null", 5) == 0) {
+                               if (found_key) {
+                                       if (nelems > 1) {
+                                               /*
+                                                * ERROR: We expected an object,
+                                                * not this identifier.
+                                                */
+                                               return (NULL);
+                                       }
+                                       return (dest);
+                               } else {
+                                       cur--;
+                                       state = DTRACE_JSON_COMMA;
+                                       break;
+                               }
+                       }
+
+                       /*
+                        * ERROR: we did not recognise the identifier as one
+                        * of those in the JSON specification.
+                        */
+                       return (NULL);
+               case DTRACE_JSON_NUMBER:
+                       if (cc == '.') {
+                               *dd++ = cc;
+                               state = DTRACE_JSON_NUMBER_FRAC;
+                               break;
+                       }
+
+                       if (cc == 'x' || cc == 'X') {
+                               /*
+                                * ERROR: specification explicitly excludes
+                                * hexidecimal or octal numbers.
+                                */
+                               return (NULL);
+                       }
+
+                       /* FALLTHRU */
+               case DTRACE_JSON_NUMBER_FRAC:
+                       if (cc == 'e' || cc == 'E') {
+                               *dd++ = cc;
+                               state = DTRACE_JSON_NUMBER_EXP;
+                               break;
+                       }
+
+                       if (cc == '+' || cc == '-') {
+                               /*
+                                * ERROR: expect sign as part of exponent only.
+                                */
+                               return (NULL);
+                       }
+                       /* FALLTHRU */
+               case DTRACE_JSON_NUMBER_EXP:
+                       if (isdigit(cc) || cc == '+' || cc == '-') {
+                               *dd++ = cc;
+                               break;
+                       }
+
+                       *dd = '\0';
+                       dd = dest; /* reset string buffer */
+                       if (found_key) {
+                               if (nelems > 1) {
+                                       /*
+                                        * ERROR: We expected an object, not
+                                        * this number.
+                                        */
+                                       return (NULL);
+                               }
+                               return (dest);
+                       }
+
+                       cur--;
+                       state = DTRACE_JSON_COMMA;
+                       break;
+               case DTRACE_JSON_VALUE:
+                       if (isspace(cc))
+                               break;
+
+                       if (cc == '{' || cc == '[') {
+                               if (nelems > 1 && found_key) {
+                                       in_array = cc == '[' ? B_TRUE : B_FALSE;
+                                       /*
+                                        * If our element selector directs us
+                                        * to descend into this nested object,
+                                        * then move to the next selector
+                                        * element in the list and restart the
+                                        * state machine.
+                                        */
+                                       while (*elem != '\0')
+                                               elem++;
+                                       elem++; /* skip the inter-element NUL */
+                                       nelems--;
+                                       dd = dest;
+                                       if (in_array) {
+                                               state = DTRACE_JSON_VALUE;
+                                               array_pos = 0;
+                                               array_elem = dtrace_strtoll(
+                                                   elem, 10, size);
+                                               found_key = array_elem == 0 ?
+                                                   B_TRUE : B_FALSE;
+                                       } else {
+                                               found_key = B_FALSE;
+                                               state = DTRACE_JSON_OBJECT;
+                                       }
+                                       break;
+                               }
+
+                               /*
+                                * Otherwise, we wish to either skip this
+                                * nested object or return it in full.
+                                */
+                               if (cc == '[')
+                                       brackets = 1;
+                               else
+                                       braces = 1;
+                               *dd++ = cc;
+                               state = DTRACE_JSON_COLLECT_OBJECT;
+                               break;
+                       }
+
+                       if (cc == '"') {
+                               state = DTRACE_JSON_STRING;
+                               break;
+                       }
+
+                       if (islower(cc)) {
+                               /*
+                                * Here we deal with true, false and null.
+                                */
+                               *dd++ = cc;
+                               state = DTRACE_JSON_IDENTIFIER;
+                               break;
+                       }
+
+                       if (cc == '-' || isdigit(cc)) {
+                               *dd++ = cc;
+                               state = DTRACE_JSON_NUMBER;
+                               break;
+                       }
+
+                       /*
+                        * ERROR: unexpected character at start of value.
+                        */
+                       return (NULL);
+               case DTRACE_JSON_COLLECT_OBJECT:
+                       if (cc == '\0')
+                               /*
+                                * ERROR: unexpected end of input.
+                                */
+                               return (NULL);
+
+                       *dd++ = cc;
+                       if (cc == '"') {
+                               collect_object = B_TRUE;
+                               state = DTRACE_JSON_STRING;
+                               break;
+                       }
+
+                       if (cc == ']') {
+                               if (brackets-- == 0) {
+                                       /*
+                                        * ERROR: unbalanced brackets.
+                                        */
+                                       return (NULL);
+                               }
+                       } else if (cc == '}') {
+                               if (braces-- == 0) {
+                                       /*
+                                        * ERROR: unbalanced braces.
+                                        */
+                                       return (NULL);
+                               }
+                       } else if (cc == '{') {
+                               braces++;
+                       } else if (cc == '[') {
+                               brackets++;
+                       }
+
+                       if (brackets == 0 && braces == 0) {
+                               if (found_key) {
+                                       *dd = '\0';
+                                       return (dest);
+                               }
+                               dd = dest; /* reset string buffer */
+                               state = DTRACE_JSON_COMMA;
+                       }
+                       break;
+               }
+       }
+       return (NULL);
+}
+
 /*
  * Emulate the execution of DTrace ID subroutines invoked by the call opcode.
  * Notice that we don't bother validating the proper number of arguments or
@@ -3661,7 +4171,8 @@ dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
 
        switch (subr) {
        case DIF_SUBR_RAND:
-               regs[rd] = (dtrace_gethrtime() * 2416 + 374441) % 1771875;
+               regs[rd] = dtrace_xoroshiro128_plus_next(
+                   state->dts_rstate[CPU->cpu_id]);
                break;
 
 #if !defined(__APPLE__)
@@ -4387,6 +4898,29 @@ dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
                break;
        }
 
+       case DIF_SUBR_STRTOLL: {
+               uintptr_t s = tupregs[0].dttk_value;
+               uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
+               size_t lim;
+               int base = 10;
+
+               if (nargs > 1) {
+                       if ((base = tupregs[1].dttk_value) <= 1 ||
+                           base > ('z' - 'a' + 1) + ('9' - '0' + 1)) {
+                               *flags |= CPU_DTRACE_ILLOP;
+                               break;
+                       }
+               }
+
+               if (!dtrace_strcanload(s, size, &lim, mstate, vstate)) {
+                       regs[rd] = INT64_MIN;
+                       break;
+               }
+
+               regs[rd] = dtrace_strtoll((char *)s, base, lim);
+               break;
+       }
+
        case DIF_SUBR_LLTOSTR: {
                int64_t i = (int64_t)tupregs[0].dttk_value;
                uint64_t val, digit;
@@ -4942,6 +5476,65 @@ inetout: regs[rd] = (uintptr_t)end + 1;
                break;
        }
 
+       case DIF_SUBR_JSON: {
+               uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
+               uintptr_t json = tupregs[0].dttk_value;
+               size_t jsonlen = dtrace_strlen((char *)json, size);
+               uintptr_t elem = tupregs[1].dttk_value;
+               size_t elemlen = dtrace_strlen((char *)elem, size);
+
+               char *dest = (char *)mstate->dtms_scratch_ptr;
+               char *elemlist = (char *)mstate->dtms_scratch_ptr + jsonlen + 1;
+               char *ee = elemlist;
+               int nelems = 1;
+               uintptr_t cur;
+
+               if (!dtrace_canload(json, jsonlen + 1, mstate, vstate) ||
+                   !dtrace_canload(elem, elemlen + 1, mstate, vstate)) {
+                       regs[rd] = 0;
+                       break;
+               }
+
+               if (!DTRACE_INSCRATCH(mstate, jsonlen + 1 + elemlen + 1)) {
+                       DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
+                       regs[rd] = 0;
+                       break;
+               }
+
+               /*
+                * Read the element selector and split it up into a packed list
+                * of strings.
+                */
+               for (cur = elem; cur < elem + elemlen; cur++) {
+                       char cc = dtrace_load8(cur);
+
+                       if (cur == elem && cc == '[') {
+                               /*
+                                * If the first element selector key is
+                                * actually an array index then ignore the
+                                * bracket.
+                                */
+                               continue;
+                       }
+
+                       if (cc == ']')
+                               continue;
+
+                       if (cc == '.' || cc == '[') {
+                               nelems++;
+                               cc = '\0';
+                       }
+
+                       *ee++ = cc;
+               }
+               *ee++ = '\0';
+
+               if ((regs[rd] = (uintptr_t)dtrace_json(size, json, elemlist,
+                   nelems, dest)) != 0)
+                       mstate->dtms_scratch_ptr += jsonlen + 1;
+               break;
+       }
+
        case DIF_SUBR_TOUPPER:
        case DIF_SUBR_TOLOWER: {
                uintptr_t src = tupregs[0].dttk_value;
@@ -4982,6 +5575,14 @@ inetout: regs[rd] = (uintptr_t)end + 1;
 
                break;
        }
+       case DIF_SUBR_STRIP:
+               if (!dtrace_is_valid_ptrauth_key(tupregs[1].dttk_value)) {
+                       DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
+                       break;
+               }
+               regs[rd] = (uint64_t)dtrace_ptrauth_strip(
+                   (void*)tupregs[0].dttk_value, tupregs[1].dttk_value);
+               break;
 
 #if defined(__APPLE__)
        case DIF_SUBR_VM_KERNEL_ADDRPERM: {
@@ -5856,6 +6457,10 @@ dtrace_dif_emulate(dtrace_difo_t *difo, dtrace_mstate_t *mstate,
                        }
                        *((uint64_t *)(uintptr_t)regs[rd]) = regs[r1];
                        break;
+               case DIF_OP_STRIP:
+                       regs[rd] = (uint64_t)dtrace_ptrauth_strip(
+                           (void*)regs[r1], r2);
+                       break;
                }
        }
 
@@ -6253,13 +6858,64 @@ dtrace_store_by_ref(dtrace_difo_t *dp, caddr_t tomax, size_t size,
        *valoffsp = valoffs;
 }
 
+/*
+ * Disables interrupts and sets the per-thread inprobe flag. When DEBUG is
+ * defined, we also assert that we are not recursing unless the probe ID is an
+ * error probe.
+ */
+static dtrace_icookie_t
+dtrace_probe_enter(dtrace_id_t id)
+{
+       thread_t thread = current_thread();
+       uint16_t inprobe;
+
+       dtrace_icookie_t cookie;
+
+       cookie = dtrace_interrupt_disable();
+
+       /*
+        * Unless this is an ERROR probe, we are not allowed to recurse in
+        * dtrace_probe(). Recursing into DTrace probe usually means that a
+        * function is instrumented that should not have been instrumented or
+        * that the ordering guarantee of the records will be violated,
+        * resulting in unexpected output. If there is an exception to this
+        * assertion, a new case should be added.
+        */
+       inprobe = dtrace_get_thread_inprobe(thread);
+       VERIFY(inprobe == 0 ||
+           id == dtrace_probeid_error);
+       ASSERT(inprobe < UINT16_MAX);
+       dtrace_set_thread_inprobe(thread, inprobe + 1);
+
+       return (cookie);
+}
+
+/*
+ * Clears the per-thread inprobe flag and enables interrupts.
+ */
+static void
+dtrace_probe_exit(dtrace_icookie_t cookie)
+{
+       thread_t thread = current_thread();
+       uint16_t inprobe = dtrace_get_thread_inprobe(thread);
+
+       ASSERT(inprobe > 0);
+       dtrace_set_thread_inprobe(thread, inprobe - 1);
+
+#if INTERRUPT_MASKED_DEBUG
+       ml_spin_debug_reset(thread);
+#endif /* INTERRUPT_MASKED_DEBUG */
+
+       dtrace_interrupt_enable(cookie);
+}
+
 /*
  * If you're looking for the epicenter of DTrace, you just found it.  This
  * is the function called by the provider to fire a probe -- from which all
  * subsequent probe-context DTrace activity emanates.
  */
-static void
-__dtrace_probe(dtrace_id_t id, uint64_t arg0, uint64_t arg1,
+void
+dtrace_probe(dtrace_id_t id, uint64_t arg0, uint64_t arg1,
     uint64_t arg2, uint64_t arg3, uint64_t arg4)
 {
        processorid_t cpuid;
@@ -6274,7 +6930,7 @@ __dtrace_probe(dtrace_id_t id, uint64_t arg0, uint64_t arg1,
        volatile uint16_t *flags;
        hrtime_t now;
 
-       cookie = dtrace_interrupt_disable();
+       cookie = dtrace_probe_enter(id);
        probe = dtrace_probes[id - 1];
        cpuid = CPU->cpu_id;
        onintr = CPU_ON_INTR(CPU);
@@ -6285,7 +6941,7 @@ __dtrace_probe(dtrace_id_t id, uint64_t arg0, uint64_t arg1,
                 * We have hit in the predicate cache; we know that
                 * this predicate would evaluate to be false.
                 */
-               dtrace_interrupt_enable(cookie);
+               dtrace_probe_exit(cookie);
                return;
        }
 
@@ -6293,7 +6949,7 @@ __dtrace_probe(dtrace_id_t id, uint64_t arg0, uint64_t arg1,
                /*
                 * We don't trace anything if we're panicking.
                 */
-               dtrace_interrupt_enable(cookie);
+               dtrace_probe_exit(cookie);
                return;
        }
 
@@ -6965,45 +7621,16 @@ __dtrace_probe(dtrace_id_t id, uint64_t arg0, uint64_t arg1,
                thread_t thread = current_thread();
                int64_t t = dtrace_get_thread_tracing(thread);
                
-               if (t >= 0) { 
+               if (t >= 0) {
                        /* Usual case, accumulate time spent here into t_dtrace_tracing */
                        dtrace_set_thread_tracing(thread, t + (dtrace_gethrtime() - now));
-               } else { 
+               } else {
                        /* Return from error recursion. No accumulation, just clear the sign bit on t_dtrace_tracing. */
-                       dtrace_set_thread_tracing(thread, (~(1ULL<<63)) & t); 
+                       dtrace_set_thread_tracing(thread, (~(1ULL<<63)) & t);
                }
        }
 
-       dtrace_interrupt_enable(cookie);
-}
-
-/*
- * APPLE NOTE:  Don't allow a thread to re-enter dtrace_probe().
- * This could occur if a probe is encountered on some function in the
- * transitive closure of the call to dtrace_probe().
- * Solaris has some strong guarantees that this won't happen.
- * The Darwin implementation is not so mature as to make those guarantees.
- * Hence, the introduction of __dtrace_probe() on xnu.
- */
-
-void
-dtrace_probe(dtrace_id_t id, uint64_t arg0, uint64_t arg1,
-    uint64_t arg2, uint64_t arg3, uint64_t arg4)
-{
-       thread_t thread = current_thread();
-       disable_preemption();
-       if (id == dtrace_probeid_error) {
-               __dtrace_probe(id, arg0, arg1, arg2, arg3, arg4);
-               dtrace_getipl(); /* Defeat tail-call optimization of __dtrace_probe() */
-       } else if (!dtrace_get_thread_reentering(thread)) {
-               dtrace_set_thread_reentering(thread, TRUE);
-               __dtrace_probe(id, arg0, arg1, arg2, arg3, arg4);
-               dtrace_set_thread_reentering(thread, FALSE);
-       }
-#if DEBUG
-       else __dtrace_probe(dtrace_probeid_error, 0, id, 1, -1, DTRACEFLT_UNKNOWN);
-#endif
-       enable_preemption();
+       dtrace_probe_exit(cookie);
 }
 
 /*
@@ -7939,22 +8566,19 @@ dtrace_register(const char *name, const dtrace_pattr_t *pap, uint32_t priv,
 
        if (pops->dtps_provide == NULL) {
                ASSERT(pops->dtps_provide_module != NULL);
-               provider->dtpv_pops.dtps_provide =
-                   (void (*)(void *, const dtrace_probedesc_t *))dtrace_nullop;
+               provider->dtpv_pops.dtps_provide = dtrace_provide_nullop;
        }
 
        if (pops->dtps_provide_module == NULL) {
                ASSERT(pops->dtps_provide != NULL);
                provider->dtpv_pops.dtps_provide_module =
-                   (void (*)(void *, struct modctl *))dtrace_nullop;
+                   dtrace_provide_module_nullop;
        }
 
        if (pops->dtps_suspend == NULL) {
                ASSERT(pops->dtps_resume == NULL);
-               provider->dtpv_pops.dtps_suspend =
-                   (void (*)(void *, dtrace_id_t, void *))dtrace_nullop;
-               provider->dtpv_pops.dtps_resume =
-                   (void (*)(void *, dtrace_id_t, void *))dtrace_nullop;
+               provider->dtpv_pops.dtps_suspend = dtrace_suspend_nullop;
+               provider->dtpv_pops.dtps_resume = dtrace_resume_nullop;
        }
 
        provider->dtpv_arg = arg;
@@ -8324,36 +8948,24 @@ dtrace_probe_create(dtrace_provider_id_t prov, const char *mod,
 
        if (id - 1 >= (dtrace_id_t)dtrace_nprobes) {
                size_t osize = dtrace_nprobes * sizeof (dtrace_probe_t *);
-               size_t nsize = osize << 1;
-
-               if (nsize == 0) {
-                       ASSERT(osize == 0);
-                       ASSERT(dtrace_probes == NULL);
-                       nsize = sizeof (dtrace_probe_t *);
-               }
+               size_t nsize = osize * 2;
 
                probes = kmem_zalloc(nsize, KM_SLEEP);
 
-               if (dtrace_probes == NULL) {
-                       ASSERT(osize == 0);
-                       dtrace_probes = probes;
-                       dtrace_nprobes = 1;
-               } else {
-                       dtrace_probe_t **oprobes = dtrace_probes;
+               dtrace_probe_t **oprobes = dtrace_probes;
 
-                       bcopy(oprobes, probes, osize);
-                       dtrace_membar_producer();
-                       dtrace_probes = probes;
+               bcopy(oprobes, probes, osize);
+               dtrace_membar_producer();
+               dtrace_probes = probes;
 
-                       dtrace_sync();
+               dtrace_sync();
 
-                       /*
-                        * All CPUs are now seeing the new probes array; we can
-                        * safely free the old array.
-                        */
-                       kmem_free(oprobes, osize);
-                       dtrace_nprobes <<= 1;
-               }
+               /*
+                * All CPUs are now seeing the new probes array; we can
+                * safely free the old array.
+                */
+               kmem_free(oprobes, osize);
+               dtrace_nprobes *= 2;
 
                ASSERT(id - 1 < (dtrace_id_t)dtrace_nprobes);
        }
@@ -8989,7 +9601,7 @@ dtrace_difo_validate(dtrace_difo_t *dp, dtrace_vstate_t *vstate, uint_t nregs,
                        if (rd >= nregs)
                                err += efunc(pc, "invalid register %u\n", rd);
                        if (rd == 0)
-                               err += efunc(pc, "cannot write to %r0\n");
+                               err += efunc(pc, "cannot write to %%r0\n");
                        break;
                case DIF_OP_NOT:
                case DIF_OP_MOV:
@@ -9001,7 +9613,7 @@ dtrace_difo_validate(dtrace_difo_t *dp, dtrace_vstate_t *vstate, uint_t nregs,
                        if (rd >= nregs)
                                err += efunc(pc, "invalid register %u\n", rd);
                        if (rd == 0)
-                               err += efunc(pc, "cannot write to %r0\n");
+                               err += efunc(pc, "cannot write to %%r0\n");
                        break;
                case DIF_OP_LDSB:
                case DIF_OP_LDSH:
@@ -9017,7 +9629,7 @@ dtrace_difo_validate(dtrace_difo_t *dp, dtrace_vstate_t *vstate, uint_t nregs,
                        if (rd >= nregs)
                                err += efunc(pc, "invalid register %u\n", rd);
                        if (rd == 0)
-                               err += efunc(pc, "cannot write to %r0\n");
+                               err += efunc(pc, "cannot write to %%r0\n");
                        if (kcheckload)
                                dp->dtdo_buf[pc] = DIF_INSTR_LOAD(op +
                                    DIF_OP_RLDSB - DIF_OP_LDSB, r1, rd);
@@ -9036,7 +9648,7 @@ dtrace_difo_validate(dtrace_difo_t *dp, dtrace_vstate_t *vstate, uint_t nregs,
                        if (rd >= nregs)
                                err += efunc(pc, "invalid register %u\n", rd);
                        if (rd == 0)
-                               err += efunc(pc, "cannot write to %r0\n");
+                               err += efunc(pc, "cannot write to %%r0\n");
                        break;
                case DIF_OP_ULDSB:
                case DIF_OP_ULDSH:
@@ -9052,7 +9664,7 @@ dtrace_difo_validate(dtrace_difo_t *dp, dtrace_vstate_t *vstate, uint_t nregs,
                        if (rd >= nregs)
                                err += efunc(pc, "invalid register %u\n", rd);
                        if (rd == 0)
-                               err += efunc(pc, "cannot write to %r0\n");
+                               err += efunc(pc, "cannot write to %%r0\n");
                        break;
                case DIF_OP_STB:
                case DIF_OP_STH:
@@ -9122,7 +9734,7 @@ dtrace_difo_validate(dtrace_difo_t *dp, dtrace_vstate_t *vstate, uint_t nregs,
                        if (rd >= nregs)
                                err += efunc(pc, "invalid register %u\n", rd);
                        if (rd == 0)
-                               err += efunc(pc, "cannot write to %r0\n");
+                               err += efunc(pc, "cannot write to %%r0\n");
                        break;
                case DIF_OP_SETS:
                        if (DIF_INSTR_STRING(instr) >= dp->dtdo_strlen) {
@@ -9132,7 +9744,7 @@ dtrace_difo_validate(dtrace_difo_t *dp, dtrace_vstate_t *vstate, uint_t nregs,
                        if (rd >= nregs)
                                err += efunc(pc, "invalid register %u\n", rd);
                        if (rd == 0)
-                               err += efunc(pc, "cannot write to %r0\n");
+                               err += efunc(pc, "cannot write to %%r0\n");
                        break;
                case DIF_OP_LDGA:
                case DIF_OP_LDTA:
@@ -9143,7 +9755,7 @@ dtrace_difo_validate(dtrace_difo_t *dp, dtrace_vstate_t *vstate, uint_t nregs,
                        if (rd >= nregs)
                                err += efunc(pc, "invalid register %u\n", rd);
                        if (rd == 0)
-                               err += efunc(pc, "cannot write to %r0\n");
+                               err += efunc(pc, "cannot write to %%r0\n");
                        break;
                case DIF_OP_LDGS:
                case DIF_OP_LDTS:
@@ -9155,7 +9767,7 @@ dtrace_difo_validate(dtrace_difo_t *dp, dtrace_vstate_t *vstate, uint_t nregs,
                        if (rd >= nregs)
                                err += efunc(pc, "invalid register %u\n", rd);
                        if (rd == 0)
-                               err += efunc(pc, "cannot write to %r0\n");
+                               err += efunc(pc, "cannot write to %%r0\n");
                        break;
                case DIF_OP_STGS:
                case DIF_OP_STTS:
@@ -9174,7 +9786,7 @@ dtrace_difo_validate(dtrace_difo_t *dp, dtrace_vstate_t *vstate, uint_t nregs,
                        if (rd >= nregs)
                                err += efunc(pc, "invalid register %u\n", rd);
                        if (rd == 0)
-                               err += efunc(pc, "cannot write to %r0\n");
+                               err += efunc(pc, "cannot write to %%r0\n");
 
                        if (subr == DIF_SUBR_COPYOUT ||
                            subr == DIF_SUBR_COPYOUTSTR ||
@@ -9199,6 +9811,16 @@ dtrace_difo_validate(dtrace_difo_t *dp, dtrace_vstate_t *vstate, uint_t nregs,
                        if (rs >= nregs)
                                err += efunc(pc, "invalid register %u\n", rs);
                        break;
+               case DIF_OP_STRIP:
+                       if (r1 >= nregs)
+                               err += efunc(pc, "invalid register %u\n", r1);
+                       if (!dtrace_is_valid_ptrauth_key(r2))
+                               err += efunc(pc, "invalid key\n");
+                       if (rd >= nregs)
+                               err += efunc(pc, "invalid register %u\n", rd);
+                       if (rd == 0)
+                               err += efunc(pc, "cannot write to %%r0\n");
+                       break;
                default:
                        err += efunc(pc, "invalid opcode %u\n",
                            DIF_INSTR_OP(instr));
@@ -9501,7 +10123,9 @@ dtrace_difo_validate_helper(dtrace_difo_t *dp)
                            subr == DIF_SUBR_INET_NTOA ||
                            subr == DIF_SUBR_INET_NTOA6 ||
                            subr == DIF_SUBR_INET_NTOP ||
+                           subr == DIF_SUBR_JSON ||
                            subr == DIF_SUBR_LLTOSTR ||
+                           subr == DIF_SUBR_STRTOLL ||
                            subr == DIF_SUBR_RINDEX ||
                            subr == DIF_SUBR_STRCHR ||
                            subr == DIF_SUBR_STRJOIN ||
@@ -11388,7 +12012,7 @@ dtrace_buffer_reserve(dtrace_buffer_t *buf, size_t needed, size_t align,
                        if (buf->dtb_cur_limit == buf->dtb_limit) {
                                buf->dtb_cur_limit = buf->dtb_size;
 
-                               atomic_add_32(&state->dts_buf_over_limit, 1);
+                               os_atomic_inc(&state->dts_buf_over_limit, relaxed);
                                /**
                                 * Set an AST on the current processor
                                 * so that we can wake up the process
@@ -11398,7 +12022,7 @@ dtrace_buffer_reserve(dtrace_buffer_t *buf, size_t needed, size_t align,
                                minor_t minor = getminor(state->dts_dev);
                                ASSERT(minor < 32);
 
-                               atomic_or_32(&dtrace_wake_clients, 1 << minor);
+                               os_atomic_or(&dtrace_wake_clients, 1 << minor, relaxed);
                                ast_dtrace_on();
                        }
                        if ((uint64_t)soffs > buf->dtb_size) {
@@ -13328,6 +13952,7 @@ dtrace_state_create(dev_t *devp, cred_t *cr, dtrace_state_t **new_state)
        dtrace_state_t *state;
        dtrace_optval_t *opt;
        int bufsize = (int)NCPU * sizeof (dtrace_buffer_t), i;
+       unsigned int cpu_it;
 
        LCK_MTX_ASSERT(&dtrace_lock, LCK_MTX_ASSERT_OWNED);
        LCK_MTX_ASSERT(&cpu_lock, LCK_MTX_ASSERT_OWNED);
@@ -13374,6 +13999,25 @@ dtrace_state_create(dev_t *devp, cred_t *cr, dtrace_state_t **new_state)
        state->dts_buffer = kmem_zalloc(bufsize, KM_SLEEP);
        state->dts_aggbuffer = kmem_zalloc(bufsize, KM_SLEEP);
        state->dts_buf_over_limit = 0;
+
+       /*
+         * Allocate and initialise the per-process per-CPU random state.
+        * SI_SUB_RANDOM < SI_SUB_DTRACE_ANON therefore entropy device is
+         * assumed to be seeded at this point (if from Fortuna seed file).
+        */
+       state->dts_rstate = kmem_zalloc(NCPU * sizeof(uint64_t*), KM_SLEEP);
+       state->dts_rstate[0] = kmem_zalloc(2 * sizeof(uint64_t), KM_SLEEP);
+       (void) read_random(state->dts_rstate[0], 2 * sizeof(uint64_t));
+       for (cpu_it = 1; cpu_it < NCPU; cpu_it++) {
+               state->dts_rstate[cpu_it] = kmem_zalloc(2 * sizeof(uint64_t), KM_SLEEP);
+               /*
+                * Each CPU is assigned a 2^64 period, non-overlapping
+                * subsequence.
+                */
+               dtrace_xoroshiro128_plus_jump(state->dts_rstate[cpu_it-1],
+                   state->dts_rstate[cpu_it]);
+       }
+
        state->dts_cleaner = CYCLIC_NONE;
        state->dts_deadman = CYCLIC_NONE;
        state->dts_vstate.dtvs_state = state;
@@ -14147,6 +14791,11 @@ dtrace_state_destroy(dtrace_state_t *state)
        dtrace_buffer_free(state->dts_buffer);
        dtrace_buffer_free(state->dts_aggbuffer);
 
+       for (i = 0; i < (int)NCPU; i++) {
+               kmem_free(state->dts_rstate[i], 2 * sizeof(uint64_t));
+       }
+       kmem_free(state->dts_rstate, NCPU * sizeof(uint64_t*));
+
        for (i = 0; i < nspec; i++)
                dtrace_buffer_free(spec[i].dtsp_buffer);
 
@@ -16487,6 +17136,10 @@ dtrace_attach(dev_info_t *devi)
 
        LCK_MTX_ASSERT(&cpu_lock, LCK_MTX_ASSERT_OWNED);
 
+       dtrace_nprobes = dtrace_nprobes_default;
+       dtrace_probes = kmem_zalloc(sizeof(dtrace_probe_t*) * dtrace_nprobes,
+           KM_SLEEP);
+
        dtrace_byprov = dtrace_hash_create(dtrace_strkey_probe_provider,
            0, /* unused */
            offsetof(dtrace_probe_t, dtpr_nextprov),
@@ -17633,7 +18286,7 @@ dtrace_ioctl(dev_t dev, u_long cmd, user_addr_t arg, int md, cred_t *cr, int *rv
                 * checking the buffer over limit count  at this point.
                 */
                if (over_limit) {
-                       uint32_t old = atomic_add_32(&state->dts_buf_over_limit, -1);
+                       uint32_t old = os_atomic_dec_orig(&state->dts_buf_over_limit, relaxed);
                        #pragma unused(old)
 
                        /*
@@ -17857,10 +18510,6 @@ dtrace_ioctl(dev_t dev, u_long cmd, user_addr_t arg, int md, cred_t *cr, int *rv
                        lck_mtx_lock(&mod_lock);
                        struct modctl* ctl = dtrace_modctl_list;
                        while (ctl) {
-                               /* Update the private probes bit */
-                               if (dtrace_provide_private_probes)
-                                       ctl->mod_flags |= MODCTL_FBT_PROVIDE_PRIVATE_PROBES;
-
                                ASSERT(!MOD_HAS_USERSPACE_SYMBOLS(ctl));
                                if (!MOD_SYMBOLS_DONE(ctl) && !MOD_IS_STATIC_KEXT(ctl)) {
                                        dtmul_count++;
@@ -17908,10 +18557,6 @@ dtrace_ioctl(dev_t dev, u_long cmd, user_addr_t arg, int md, cred_t *cr, int *rv
                
                struct modctl* ctl = dtrace_modctl_list;
                while (ctl) {
-                       /* Update the private probes bit */
-                       if (dtrace_provide_private_probes)
-                               ctl->mod_flags |= MODCTL_FBT_PROVIDE_PRIVATE_PROBES;
-
                        /*
                         * We assume that userspace symbols will be "better" than kernel level symbols,
                         * as userspace can search for dSYM(s) and symbol'd binaries. Even if kernel syms
@@ -18029,10 +18674,6 @@ dtrace_ioctl(dev_t dev, u_long cmd, user_addr_t arg, int md, cred_t *cr, int *rv
                
                struct modctl* ctl = dtrace_modctl_list;
                while (ctl) {
-                       /* Update the private probes bit */
-                       if (dtrace_provide_private_probes)
-                               ctl->mod_flags |= MODCTL_FBT_PROVIDE_PRIVATE_PROBES;
-
                        ASSERT(!MOD_HAS_USERSPACE_SYMBOLS(ctl));
                        if (MOD_HAS_UUID(ctl) && !MOD_SYMBOLS_DONE(ctl) && memcmp(module_symbols->dtmodsyms_uuid, ctl->mod_uuid, sizeof(UUID)) == 0) {
                                dtrace_provider_t *prv;
@@ -18396,7 +19037,7 @@ void
 dtrace_ast(void)
 {
        int i;
-       uint32_t clients = atomic_and_32(&dtrace_wake_clients, 0);
+       uint32_t clients = os_atomic_xchg(&dtrace_wake_clients, 0, relaxed);
        if (clients == 0)
                return;
        /**
@@ -18618,6 +19259,11 @@ dtrace_init( void )
                                break;
                }
 
+#if CONFIG_DTRACE
+        if (dtrace_dof_mode != DTRACE_DOF_MODE_NEVER)
+            commpage_update_dof(true);
+#endif
+
                gDTraceInited = 1;
 
        } else
@@ -18648,10 +19294,6 @@ dtrace_postinit(void)
        if (dtrace_module_loaded(&fake_kernel_kmod, 0) != 0) {
                printf("dtrace_postinit: Could not register mach_kernel modctl\n");
        }
-
-       if (!PE_parse_boot_argn("dtrace_provide_private_probes", &dtrace_provide_private_probes, sizeof (dtrace_provide_private_probes))) {
-                       dtrace_provide_private_probes = 0;
-       }
        
        (void)OSKextRegisterKextsWithDTrace();
 }