Print this page
OS-1723 DTrace should speak JSON
Reviewed by: Bryan Cantrill <bmc@joyent.com>


  75 #include <sys/kmem.h>
  76 #include <sys/strsubr.h>
  77 #include <sys/sysmacros.h>
  78 #include <sys/dtrace_impl.h>
  79 #include <sys/atomic.h>
  80 #include <sys/cmn_err.h>
  81 #include <sys/mutex_impl.h>
  82 #include <sys/rwlock_impl.h>
  83 #include <sys/ctf_api.h>
  84 #include <sys/panic.h>
  85 #include <sys/priv_impl.h>
  86 #include <sys/policy.h>
  87 #include <sys/cred_impl.h>
  88 #include <sys/procfs_isa.h>
  89 #include <sys/taskq.h>
  90 #include <sys/mkdev.h>
  91 #include <sys/kdi.h>
  92 #include <sys/zone.h>
  93 #include <sys/socket.h>
  94 #include <netinet/in.h>

  95 
  96 /*
  97  * DTrace Tunable Variables
  98  *
  99  * The following variables may be tuned by adding a line to /etc/system that
 100  * includes both the name of the DTrace module ("dtrace") and the name of the
 101  * variable.  For example:
 102  *
 103  *   set dtrace:dtrace_destructive_disallow = 1
 104  *
 105  * In general, the only variables that one should be tuning this way are those
 106  * that affect system-wide DTrace behavior, and for which the default behavior
 107  * is undesirable.  Most of these variables are tunable on a per-consumer
 108  * basis using DTrace options, and need not be tuned on a system-wide basis.
 109  * When tuning these variables, avoid pathological values; while some attempt
 110  * is made to verify the integrity of these variables, they are not considered
 111  * part of the supported interface to DTrace, and they are therefore not
 112  * checked comprehensively.  Further, these variables should not be tuned
 113  * dynamically via "mdb -kw" or other means; they should only be tuned via
 114  * /etc/system.


 860                 if (state != NULL) {
 861                         strsize = state->dts_options[DTRACEOPT_STRSIZE];
 862                 } else {
 863                         /*
 864                          * In helper context, we have a NULL state; fall back
 865                          * to using the system-wide default for the string size
 866                          * in this case.
 867                          */
 868                         strsize = dtrace_strsize_default;
 869                 }
 870 
 871                 sz = dtrace_strlen(src, strsize) + 1;
 872         } else {
 873                 sz = type->dtdt_size;
 874         }
 875 
 876         return (dtrace_canload((uintptr_t)src, sz, mstate, vstate));
 877 }
 878 
 879 /*




















































 880  * Compare two strings using safe loads.
 881  */
 882 static int
 883 dtrace_strncmp(char *s1, char *s2, size_t limit)
 884 {
 885         uint8_t c1, c2;
 886         volatile uint16_t *flags;
 887 
 888         if (s1 == s2 || limit == 0)
 889                 return (0);
 890 
 891         flags = (volatile uint16_t *)&cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
 892 
 893         do {
 894                 if (s1 == NULL) {
 895                         c1 = '\0';
 896                 } else {
 897                         c1 = dtrace_load8((uintptr_t)s1++);
 898                 }
 899 


3336                 if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU))
3337                         return (0);
3338 
3339                 /*
3340                  * It is always safe to dereference one's own t_lwp pointer in
3341                  * the event that this pointer is non-NULL.  (This is true
3342                  * because threads and lwps don't clean up their own state --
3343                  * they leave that task to whomever reaps them.)
3344                  */
3345                 if ((lwp = curthread->t_lwp) == NULL)
3346                         return (0);
3347 
3348                 return ((uint64_t)lwp->lwp_errno);
3349         }
3350         default:
3351                 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
3352                 return (0);
3353         }
3354 }
3355 

















3356 /*
























































































































































































































































































































































































































































3357  * Emulate the execution of DTrace ID subroutines invoked by the call opcode.
3358  * Notice that we don't bother validating the proper number of arguments or
3359  * their types in the tuple stack.  This isn't needed because all argument
3360  * interpretation is safe because of our load safety -- the worst that can
3361  * happen is that a bogus program can obtain bogus results.
3362  */
3363 static void
3364 dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
3365     dtrace_key_t *tupregs, int nargs,
3366     dtrace_mstate_t *mstate, dtrace_state_t *state)
3367 {
3368         volatile uint16_t *flags = &cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
3369         volatile uintptr_t *illval = &cpu_core[CPU->cpu_id].cpuc_dtrace_illval;
3370         dtrace_vstate_t *vstate = &state->dts_vstate;
3371 
3372         union {
3373                 mutex_impl_t mi;
3374                 uint64_t mx;
3375         } m;
3376 


4036                 if (index >= len || index < 0) {
4037                         remaining = 0;
4038                 } else if (remaining < 0) {
4039                         remaining += len - index;
4040                 } else if (index + remaining > size) {
4041                         remaining = size - index;
4042                 }
4043 
4044                 for (i = 0; i < remaining; i++) {
4045                         if ((d[i] = dtrace_load8(s + index + i)) == '\0')
4046                                 break;
4047                 }
4048 
4049                 d[i] = '\0';
4050 
4051                 mstate->dtms_scratch_ptr += size;
4052                 regs[rd] = (uintptr_t)d;
4053                 break;
4054         }
4055 



























































4056         case DIF_SUBR_TOUPPER:
4057         case DIF_SUBR_TOLOWER: {
4058                 uintptr_t s = tupregs[0].dttk_value;
4059                 uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
4060                 char *dest = (char *)mstate->dtms_scratch_ptr, c;
4061                 size_t len = dtrace_strlen((char *)s, size);
4062                 char lower, upper, convert;
4063                 int64_t i;
4064 
4065                 if (subr == DIF_SUBR_TOUPPER) {
4066                         lower = 'a';
4067                         upper = 'z';
4068                         convert = 'A';
4069                 } else {
4070                         lower = 'A';
4071                         upper = 'Z';
4072                         convert = 'a';
4073                 }
4074 
4075                 if (!dtrace_canload(s, len + 1, mstate, vstate)) {


4343 
4344                 for (;;) {
4345                         if (i >= size) {
4346                                 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4347                                 regs[rd] = NULL;
4348                                 break;
4349                         }
4350 
4351                         if ((d[i++] = dtrace_load8(s2++)) == '\0')
4352                                 break;
4353                 }
4354 
4355                 if (i < size) {
4356                         mstate->dtms_scratch_ptr += i;
4357                         regs[rd] = (uintptr_t)d;
4358                 }
4359 
4360                 break;
4361         }
4362 






















4363         case DIF_SUBR_LLTOSTR: {
4364                 int64_t i = (int64_t)tupregs[0].dttk_value;
4365                 uint64_t val, digit;
4366                 uint64_t size = 65;     /* enough room for 2^64 in binary */
4367                 char *end = (char *)mstate->dtms_scratch_ptr + size - 1;
4368                 int base = 10;
4369 
4370                 if (nargs > 1) {
4371                         if ((base = tupregs[1].dttk_value) <= 1 ||
4372                             base > ('z' - 'a' + 1) + ('9' - '0' + 1)) {
4373                                 *flags |= CPU_DTRACE_ILLOP;
4374                                 break;
4375                         }
4376                 }
4377 
4378                 val = (base == 10 && i < 0) ? i * -1 : i;
4379 
4380                 if (!DTRACE_INSCRATCH(mstate, size)) {
4381                         DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4382                         regs[rd] = NULL;


8872                 case DIF_OP_LDTAA:
8873                         err += efunc(pc, "illegal dynamic variable load\n");
8874                         break;
8875 
8876                 case DIF_OP_STTS:
8877                 case DIF_OP_STGAA:
8878                 case DIF_OP_STTAA:
8879                         err += efunc(pc, "illegal dynamic variable store\n");
8880                         break;
8881 
8882                 case DIF_OP_CALL:
8883                         if (subr == DIF_SUBR_ALLOCA ||
8884                             subr == DIF_SUBR_BCOPY ||
8885                             subr == DIF_SUBR_COPYIN ||
8886                             subr == DIF_SUBR_COPYINTO ||
8887                             subr == DIF_SUBR_COPYINSTR ||
8888                             subr == DIF_SUBR_INDEX ||
8889                             subr == DIF_SUBR_INET_NTOA ||
8890                             subr == DIF_SUBR_INET_NTOA6 ||
8891                             subr == DIF_SUBR_INET_NTOP ||

8892                             subr == DIF_SUBR_LLTOSTR ||

8893                             subr == DIF_SUBR_RINDEX ||
8894                             subr == DIF_SUBR_STRCHR ||
8895                             subr == DIF_SUBR_STRJOIN ||
8896                             subr == DIF_SUBR_STRRCHR ||
8897                             subr == DIF_SUBR_STRSTR ||
8898                             subr == DIF_SUBR_HTONS ||
8899                             subr == DIF_SUBR_HTONL ||
8900                             subr == DIF_SUBR_HTONLL ||
8901                             subr == DIF_SUBR_NTOHS ||
8902                             subr == DIF_SUBR_NTOHL ||
8903                             subr == DIF_SUBR_NTOHLL)
8904                                 break;
8905 
8906                         err += efunc(pc, "invalid subr %u\n", subr);
8907                         break;
8908 
8909                 default:
8910                         err += efunc(pc, "invalid opcode %u\n",
8911                             DIF_INSTR_OP(instr));
8912                 }




  75 #include <sys/kmem.h>
  76 #include <sys/strsubr.h>
  77 #include <sys/sysmacros.h>
  78 #include <sys/dtrace_impl.h>
  79 #include <sys/atomic.h>
  80 #include <sys/cmn_err.h>
  81 #include <sys/mutex_impl.h>
  82 #include <sys/rwlock_impl.h>
  83 #include <sys/ctf_api.h>
  84 #include <sys/panic.h>
  85 #include <sys/priv_impl.h>
  86 #include <sys/policy.h>
  87 #include <sys/cred_impl.h>
  88 #include <sys/procfs_isa.h>
  89 #include <sys/taskq.h>
  90 #include <sys/mkdev.h>
  91 #include <sys/kdi.h>
  92 #include <sys/zone.h>
  93 #include <sys/socket.h>
  94 #include <netinet/in.h>
  95 #include "strtolctype.h"
  96 
  97 /*
  98  * DTrace Tunable Variables
  99  *
 100  * The following variables may be tuned by adding a line to /etc/system that
 101  * includes both the name of the DTrace module ("dtrace") and the name of the
 102  * variable.  For example:
 103  *
 104  *   set dtrace:dtrace_destructive_disallow = 1
 105  *
 106  * In general, the only variables that one should be tuning this way are those
 107  * that affect system-wide DTrace behavior, and for which the default behavior
 108  * is undesirable.  Most of these variables are tunable on a per-consumer
 109  * basis using DTrace options, and need not be tuned on a system-wide basis.
 110  * When tuning these variables, avoid pathological values; while some attempt
 111  * is made to verify the integrity of these variables, they are not considered
 112  * part of the supported interface to DTrace, and they are therefore not
 113  * checked comprehensively.  Further, these variables should not be tuned
 114  * dynamically via "mdb -kw" or other means; they should only be tuned via
 115  * /etc/system.


 861                 if (state != NULL) {
 862                         strsize = state->dts_options[DTRACEOPT_STRSIZE];
 863                 } else {
 864                         /*
 865                          * In helper context, we have a NULL state; fall back
 866                          * to using the system-wide default for the string size
 867                          * in this case.
 868                          */
 869                         strsize = dtrace_strsize_default;
 870                 }
 871 
 872                 sz = dtrace_strlen(src, strsize) + 1;
 873         } else {
 874                 sz = type->dtdt_size;
 875         }
 876 
 877         return (dtrace_canload((uintptr_t)src, sz, mstate, vstate));
 878 }
 879 
 880 /*
 881  * Convert a string to a signed integer using safe loads.
 882  *
 883  * NOTE: This function uses various macros from strtolctype.h to manipulate
 884  * digit values, etc -- these have all been checked to ensure they make
 885  * no additional function calls.
 886  */
 887 static int64_t
 888 dtrace_strtoll(char *input, int base, size_t limit)
 889 {
 890         uintptr_t pos = (uintptr_t)input;
 891         int64_t val = 0;
 892         int x;
 893         boolean_t neg = B_FALSE;
 894         char c, cc, ccc;
 895         uintptr_t end = pos + limit;
 896 
 897         /*
 898          * Consume any whitespace preceding digits.
 899          */
 900         while ((c = dtrace_load8(pos)) == ' ' || c == '\t')
 901                 pos++;
 902 
 903         /*
 904          * Handle an explicit sign if one is present.
 905          */
 906         if (c == '-' || c == '+') {
 907                 if (c == '-')
 908                         neg = B_TRUE;
 909                 c = dtrace_load8(++pos);
 910         }
 911 
 912         /*
 913          * Check for an explicit hexadecimal prefix ("0x" or "0X") and skip it
 914          * if present.
 915          */
 916         if (base == 16 && c == '0' && ((cc = dtrace_load8(pos + 1)) == 'x' ||
 917             cc == 'X') && isxdigit(ccc = dtrace_load8(pos + 2))) {
 918                 pos += 2;
 919                 c = ccc;
 920         }
 921 
 922         /*
 923          * Read in contiguous digits until the first non-digit character.
 924          */
 925         for (; pos < end && c != '\0' && lisalnum(c) && (x = DIGIT(c)) < base;
 926             c = dtrace_load8(++pos))
 927                 val = val * base + x;
 928 
 929         return (neg ? -val : val);
 930 }
 931 
 932 /*
 933  * Compare two strings using safe loads.
 934  */
 935 static int
 936 dtrace_strncmp(char *s1, char *s2, size_t limit)
 937 {
 938         uint8_t c1, c2;
 939         volatile uint16_t *flags;
 940 
 941         if (s1 == s2 || limit == 0)
 942                 return (0);
 943 
 944         flags = (volatile uint16_t *)&cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
 945 
 946         do {
 947                 if (s1 == NULL) {
 948                         c1 = '\0';
 949                 } else {
 950                         c1 = dtrace_load8((uintptr_t)s1++);
 951                 }
 952 


3389                 if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU))
3390                         return (0);
3391 
3392                 /*
3393                  * It is always safe to dereference one's own t_lwp pointer in
3394                  * the event that this pointer is non-NULL.  (This is true
3395                  * because threads and lwps don't clean up their own state --
3396                  * they leave that task to whomever reaps them.)
3397                  */
3398                 if ((lwp = curthread->t_lwp) == NULL)
3399                         return (0);
3400 
3401                 return ((uint64_t)lwp->lwp_errno);
3402         }
3403         default:
3404                 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
3405                 return (0);
3406         }
3407 }
3408 
3409 
3410 typedef enum dtrace_json_state {
3411         DTRACE_JSON_REST = 1,
3412         DTRACE_JSON_OBJECT,
3413         DTRACE_JSON_STRING,
3414         DTRACE_JSON_STRING_ESCAPE,
3415         DTRACE_JSON_STRING_ESCAPE_UNICODE,
3416         DTRACE_JSON_COLON,
3417         DTRACE_JSON_COMMA,
3418         DTRACE_JSON_VALUE,
3419         DTRACE_JSON_IDENTIFIER,
3420         DTRACE_JSON_NUMBER,
3421         DTRACE_JSON_NUMBER_FRAC,
3422         DTRACE_JSON_NUMBER_EXP,
3423         DTRACE_JSON_COLLECT_OBJECT
3424 } dtrace_json_state_t;
3425 
3426 /*
3427  * This function possesses just enough knowledge about JSON to extract a single
3428  * value from a JSON string and store it in the scratch buffer.  It is able
3429  * to extract nested object values, and members of arrays by index.
3430  *
3431  * elemlist is a list of JSON keys, stored as packed NUL-terminated strings, to
3432  * be looked up as we descend into the object tree.  e.g.
3433  *
3434  *    foo[0].bar.baz[32] --> "foo" NUL "0" NUL "bar" NUL "baz" NUL "32" NUL
3435  *       with nelems = 5.
3436  *
3437  * The run time of this function must be bounded above by strsize to limit the
3438  * amount of work done in probe context.  As such, it is implemented as a
3439  * simple state machine, reading one character at a time using safe loads
3440  * until we find the requested element, hit a parsing error or run off the
3441  * end of the object or string.
3442  *
3443  * As there is no way for a subroutine to return an error without interrupting
3444  * clause execution, we simply return NULL in the event of a missing key or any
3445  * other error condition.  Each NULL return in this function is commented with
3446  * the error condition it represents -- parsing or otherwise.
3447  *
3448  * The set of states for the state machine closely matches the JSON
3449  * specification (http://json.org/).  Briefly:
3450  *
3451  *   DTRACE_JSON_REST:
3452  *     Skip whitespace until we find either a top-level Object, moving
3453  *     to DTRACE_JSON_OBJECT; or an Array, moving to DTRACE_JSON_VALUE.
3454  *
3455  *   DTRACE_JSON_OBJECT:
3456  *     Locate the next key String in an Object.  Sets a flag to denote
3457  *     the next String as a key string and moves to DTRACE_JSON_STRING.
3458  *
3459  *   DTRACE_JSON_COLON:
3460  *     Skip whitespace until we find the colon that separates key Strings
3461  *     from their values.  Once found, move to DTRACE_JSON_VALUE.
3462  *
3463  *   DTRACE_JSON_VALUE:
3464  *     Detects the type of the next value (String, Number, Identifier, Object
3465  *     or Array) and routes to the states that process that type.  Here we also
3466  *     deal with the element selector list if we are requested to traverse down
3467  *     into the object tree.
3468  *
3469  *   DTRACE_JSON_COMMA:
3470  *     Skip whitespace until we find the comma that separates key-value pairs
3471  *     in Objects (returning to DTRACE_JSON_OBJECT) or values in Arrays
3472  *     (similarly DTRACE_JSON_VALUE).  All following literal value processing
3473  *     states return to this state at the end of their value, unless otherwise
3474  *     noted.
3475  *
3476  *   DTRACE_JSON_NUMBER, DTRACE_JSON_NUMBER_FRAC, DTRACE_JSON_NUMBER_EXP:
3477  *     Processes a Number literal from the JSON, including any exponent
3478  *     component that may be present.  Numbers are returned as strings, which
3479  *     may be passed to strtoll() if an integer is required.
3480  *
3481  *   DTRACE_JSON_IDENTIFIER:
3482  *     Processes a "true", "false" or "null" literal in the JSON.
3483  *
3484  *   DTRACE_JSON_STRING, DTRACE_JSON_STRING_ESCAPE,
3485  *   DTRACE_JSON_STRING_ESCAPE_UNICODE:
3486  *     Processes a String literal from the JSON, whether the String denotes
3487  *     a key, a value or part of a larger Object.  Handles all escape sequences
3488  *     present in the specification, including four-digit unicode characters,
3489  *     but merely includes the escape sequence without converting it to the
3490  *     actual escaped character.  If the String is flagged as a key, we
3491  *     move to DTRACE_JSON_COLON rather than DTRACE_JSON_COMMA.
3492  *
3493  *   DTRACE_JSON_COLLECT_OBJECT:
3494  *     This state collects an entire Object (or Array), correctly handling
3495  *     embedded strings.  If the full element selector list matches this nested
3496  *     object, we return the Object in full as a string.  If not, we use this
3497  *     state to skip to the next value at this level and continue processing.
3498  *
3499  * NOTE: This function uses various macros from strtolctype.h to manipulate
3500  * digit values, etc -- these have all been checked to ensure they make
3501  * no additional function calls.
3502  */
3503 static char *
3504 dtrace_json(uint64_t size, uintptr_t json, char *elemlist, int nelems,
3505     char *dest)
3506 {
3507         dtrace_json_state_t state = DTRACE_JSON_REST;
3508         int64_t array_elem = INT64_MIN;
3509         int64_t array_pos = 0;
3510         uint8_t escape_unicount = 0;
3511         boolean_t string_is_key = B_FALSE;
3512         boolean_t collect_object = B_FALSE;
3513         boolean_t found_key = B_FALSE;
3514         boolean_t in_array = B_FALSE;
3515         uint32_t braces = 0, brackets = 0;
3516         char *elem = elemlist;
3517         char *dd = dest;
3518         uintptr_t cur;
3519 
3520         for (cur = json; cur < json + size; cur++) {
3521                 char cc = dtrace_load8(cur);
3522                 if (cc == '\0')
3523                         return (NULL);
3524 
3525                 switch (state) {
3526                 case DTRACE_JSON_REST:
3527                         if (isspace(cc))
3528                                 break;
3529 
3530                         if (cc == '{') {
3531                                 state = DTRACE_JSON_OBJECT;
3532                                 break;
3533                         }
3534 
3535                         if (cc == '[') {
3536                                 in_array = B_TRUE;
3537                                 array_pos = 0;
3538                                 array_elem = dtrace_strtoll(elem, 10, size);
3539                                 found_key = array_elem == 0 ? B_TRUE : B_FALSE;
3540                                 state = DTRACE_JSON_VALUE;
3541                                 break;
3542                         }
3543 
3544                         /*
3545                          * ERROR: expected to find a top-level object or array.
3546                          */
3547                         return (NULL);
3548                 case DTRACE_JSON_OBJECT:
3549                         if (isspace(cc))
3550                                 break;
3551 
3552                         if (cc == '"') {
3553                                 state = DTRACE_JSON_STRING;
3554                                 string_is_key = B_TRUE;
3555                                 break;
3556                         }
3557 
3558                         /*
3559                          * ERROR: either the object did not start with a key
3560                          * string, or we've run off the end of the object
3561                          * without finding the requested key.
3562                          */
3563                         return (NULL);
3564                 case DTRACE_JSON_STRING:
3565                         if (cc == '\\') {
3566                                 *dd++ = '\\';
3567                                 state = DTRACE_JSON_STRING_ESCAPE;
3568                                 break;
3569                         }
3570 
3571                         if (cc == '"') {
3572                                 if (collect_object) {
3573                                         /*
3574                                          * We don't reset the dest here, as
3575                                          * the string is part of a larger
3576                                          * object being collected.
3577                                          */
3578                                         *dd++ = cc;
3579                                         collect_object = B_FALSE;
3580                                         state = DTRACE_JSON_COLLECT_OBJECT;
3581                                         break;
3582                                 }
3583                                 *dd = '\0';
3584                                 dd = dest; /* reset string buffer */
3585                                 if (string_is_key) {
3586                                         if (dtrace_strncmp(dest, elem,
3587                                             size) == 0)
3588                                                 found_key = B_TRUE;
3589                                 } else if (found_key) {
3590                                         if (nelems > 1) {
3591                                                 /*
3592                                                  * We expected an object, not
3593                                                  * this string.
3594                                                  */
3595                                                 return (NULL);
3596                                         }
3597                                         return (dest);
3598                                 }
3599                                 state = string_is_key ? DTRACE_JSON_COLON :
3600                                     DTRACE_JSON_COMMA;
3601                                 string_is_key = B_FALSE;
3602                                 break;
3603                         }
3604 
3605                         *dd++ = cc;
3606                         break;
3607                 case DTRACE_JSON_STRING_ESCAPE:
3608                         *dd++ = cc;
3609                         if (cc == 'u') {
3610                                 escape_unicount = 0;
3611                                 state = DTRACE_JSON_STRING_ESCAPE_UNICODE;
3612                         } else {
3613                                 state = DTRACE_JSON_STRING;
3614                         }
3615                         break;
3616                 case DTRACE_JSON_STRING_ESCAPE_UNICODE:
3617                         if (!isxdigit(cc)) {
3618                                 /*
3619                                  * ERROR: invalid unicode escape, expected
3620                                  * four valid hexidecimal digits.
3621                                  */
3622                                 return (NULL);
3623                         }
3624 
3625                         *dd++ = cc;
3626                         if (++escape_unicount == 4)
3627                                 state = DTRACE_JSON_STRING;
3628                         break;
3629                 case DTRACE_JSON_COLON:
3630                         if (isspace(cc))
3631                                 break;
3632 
3633                         if (cc == ':') {
3634                                 state = DTRACE_JSON_VALUE;
3635                                 break;
3636                         }
3637 
3638                         /*
3639                          * ERROR: expected a colon.
3640                          */
3641                         return (NULL);
3642                 case DTRACE_JSON_COMMA:
3643                         if (isspace(cc))
3644                                 break;
3645 
3646                         if (cc == ',') {
3647                                 if (in_array) {
3648                                         state = DTRACE_JSON_VALUE;
3649                                         if (++array_pos == array_elem)
3650                                                 found_key = B_TRUE;
3651                                 } else {
3652                                         state = DTRACE_JSON_OBJECT;
3653                                 }
3654                                 break;
3655                         }
3656 
3657                         /*
3658                          * ERROR: either we hit an unexpected character, or
3659                          * we reached the end of the object or array without
3660                          * finding the requested key.
3661                          */
3662                         return (NULL);
3663                 case DTRACE_JSON_IDENTIFIER:
3664                         if (islower(cc)) {
3665                                 *dd++ = cc;
3666                                 break;
3667                         }
3668 
3669                         *dd = '\0';
3670                         dd = dest; /* reset string buffer */
3671 
3672                         if (dtrace_strncmp(dest, "true", 5) == 0 ||
3673                             dtrace_strncmp(dest, "false", 6) == 0 ||
3674                             dtrace_strncmp(dest, "null", 5) == 0) {
3675                                 if (found_key) {
3676                                         if (nelems > 1) {
3677                                                 /*
3678                                                  * ERROR: We expected an object,
3679                                                  * not this identifier.
3680                                                  */
3681                                                 return (NULL);
3682                                         }
3683                                         return (dest);
3684                                 } else {
3685                                         cur--;
3686                                         state = DTRACE_JSON_COMMA;
3687                                         break;
3688                                 }
3689                         }
3690 
3691                         /*
3692                          * ERROR: we did not recognise the identifier as one
3693                          * of those in the JSON specification.
3694                          */
3695                         return (NULL);
3696                 case DTRACE_JSON_NUMBER:
3697                         if (cc == '.') {
3698                                 *dd++ = cc;
3699                                 state = DTRACE_JSON_NUMBER_FRAC;
3700                                 break;
3701                         }
3702 
3703                         if (cc == 'x' || cc == 'X') {
3704                                 /*
3705                                  * ERROR: specification explicitly excludes
3706                                  * hexidecimal or octal numbers.
3707                                  */
3708                                 return (NULL);
3709                         }
3710 
3711                         /* FALLTHRU */
3712                 case DTRACE_JSON_NUMBER_FRAC:
3713                         if (cc == 'e' || cc == 'E') {
3714                                 *dd++ = cc;
3715                                 state = DTRACE_JSON_NUMBER_EXP;
3716                                 break;
3717                         }
3718 
3719                         if (cc == '+' || cc == '-') {
3720                                 /*
3721                                  * ERROR: expect sign as part of exponent only.
3722                                  */
3723                                 return (NULL);
3724                         }
3725                         /* FALLTHRU */
3726                 case DTRACE_JSON_NUMBER_EXP:
3727                         if (isdigit(cc) || cc == '+' || cc == '-') {
3728                                 *dd++ = cc;
3729                                 break;
3730                         }
3731 
3732                         *dd = '\0';
3733                         dd = dest; /* reset string buffer */
3734                         if (found_key) {
3735                                 if (nelems > 1) {
3736                                         /*
3737                                          * ERROR: We expected an object, not
3738                                          * this number.
3739                                          */
3740                                         return (NULL);
3741                                 }
3742                                 return (dest);
3743                         }
3744 
3745                         cur--;
3746                         state = DTRACE_JSON_COMMA;
3747                         break;
3748                 case DTRACE_JSON_VALUE:
3749                         if (isspace(cc))
3750                                 break;
3751 
3752                         if (cc == '{' || cc == '[') {
3753                                 if (nelems > 1 && found_key) {
3754                                         in_array = cc == '[' ? B_TRUE : B_FALSE;
3755                                         /*
3756                                          * If our element selector directs us
3757                                          * to descend into this nested object,
3758                                          * then move to the next selector
3759                                          * element in the list and restart the
3760                                          * state machine.
3761                                          */
3762                                         while (*elem != '\0')
3763                                                 elem++;
3764                                         elem++; /* skip the inter-element NUL */
3765                                         nelems--;
3766                                         dd = dest;
3767                                         if (in_array) {
3768                                                 state = DTRACE_JSON_VALUE;
3769                                                 array_pos = 0;
3770                                                 array_elem = dtrace_strtoll(
3771                                                     elem, 10, size);
3772                                                 found_key = array_elem == 0 ?
3773                                                     B_TRUE : B_FALSE;
3774                                         } else {
3775                                                 found_key = B_FALSE;
3776                                                 state = DTRACE_JSON_OBJECT;
3777                                         }
3778                                         break;
3779                                 }
3780 
3781                                 /*
3782                                  * Otherwise, we wish to either skip this
3783                                  * nested object or return it in full.
3784                                  */
3785                                 if (cc == '[')
3786                                         brackets = 1;
3787                                 else
3788                                         braces = 1;
3789                                 *dd++ = cc;
3790                                 state = DTRACE_JSON_COLLECT_OBJECT;
3791                                 break;
3792                         }
3793 
3794                         if (cc == '"') {
3795                                 state = DTRACE_JSON_STRING;
3796                                 break;
3797                         }
3798 
3799                         if (islower(cc)) {
3800                                 /*
3801                                  * Here we deal with true, false and null.
3802                                  */
3803                                 *dd++ = cc;
3804                                 state = DTRACE_JSON_IDENTIFIER;
3805                                 break;
3806                         }
3807 
3808                         if (cc == '-' || isdigit(cc)) {
3809                                 *dd++ = cc;
3810                                 state = DTRACE_JSON_NUMBER;
3811                                 break;
3812                         }
3813 
3814                         /*
3815                          * ERROR: unexpected character at start of value.
3816                          */
3817                         return (NULL);
3818                 case DTRACE_JSON_COLLECT_OBJECT:
3819                         if (cc == '\0')
3820                                 /*
3821                                  * ERROR: unexpected end of input.
3822                                  */
3823                                 return (NULL);
3824 
3825                         *dd++ = cc;
3826                         if (cc == '"') {
3827                                 collect_object = B_TRUE;
3828                                 state = DTRACE_JSON_STRING;
3829                                 break;
3830                         }
3831 
3832                         if (cc == ']') {
3833                                 if (brackets-- == 0) {
3834                                         /*
3835                                          * ERROR: unbalanced brackets.
3836                                          */
3837                                         return (NULL);
3838                                 }
3839                         } else if (cc == '}') {
3840                                 if (braces-- == 0) {
3841                                         /*
3842                                          * ERROR: unbalanced braces.
3843                                          */
3844                                         return (NULL);
3845                                 }
3846                         } else if (cc == '{') {
3847                                 braces++;
3848                         } else if (cc == '[') {
3849                                 brackets++;
3850                         }
3851 
3852                         if (brackets == 0 && braces == 0) {
3853                                 if (found_key) {
3854                                         *dd = '\0';
3855                                         return (dest);
3856                                 }
3857                                 dd = dest; /* reset string buffer */
3858                                 state = DTRACE_JSON_COMMA;
3859                         }
3860                         break;
3861                 }
3862         }
3863         return (NULL);
3864 }
3865 
3866 /*
3867  * Emulate the execution of DTrace ID subroutines invoked by the call opcode.
3868  * Notice that we don't bother validating the proper number of arguments or
3869  * their types in the tuple stack.  This isn't needed because all argument
3870  * interpretation is safe because of our load safety -- the worst that can
3871  * happen is that a bogus program can obtain bogus results.
3872  */
3873 static void
3874 dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
3875     dtrace_key_t *tupregs, int nargs,
3876     dtrace_mstate_t *mstate, dtrace_state_t *state)
3877 {
3878         volatile uint16_t *flags = &cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
3879         volatile uintptr_t *illval = &cpu_core[CPU->cpu_id].cpuc_dtrace_illval;
3880         dtrace_vstate_t *vstate = &state->dts_vstate;
3881 
3882         union {
3883                 mutex_impl_t mi;
3884                 uint64_t mx;
3885         } m;
3886 


4546                 if (index >= len || index < 0) {
4547                         remaining = 0;
4548                 } else if (remaining < 0) {
4549                         remaining += len - index;
4550                 } else if (index + remaining > size) {
4551                         remaining = size - index;
4552                 }
4553 
4554                 for (i = 0; i < remaining; i++) {
4555                         if ((d[i] = dtrace_load8(s + index + i)) == '\0')
4556                                 break;
4557                 }
4558 
4559                 d[i] = '\0';
4560 
4561                 mstate->dtms_scratch_ptr += size;
4562                 regs[rd] = (uintptr_t)d;
4563                 break;
4564         }
4565 
4566         case DIF_SUBR_JSON: {
4567                 uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
4568                 uintptr_t json = tupregs[0].dttk_value;
4569                 size_t jsonlen = dtrace_strlen((char *)json, size);
4570                 uintptr_t elem = tupregs[1].dttk_value;
4571                 size_t elemlen = dtrace_strlen((char *)elem, size);
4572 
4573                 char *dest = (char *)mstate->dtms_scratch_ptr;
4574                 char *elemlist = (char *)mstate->dtms_scratch_ptr + jsonlen + 1;
4575                 char *ee = elemlist;
4576                 int nelems = 1;
4577                 uintptr_t cur;
4578 
4579                 if (!dtrace_canload(json, jsonlen + 1, mstate, vstate) ||
4580                     !dtrace_canload(elem, elemlen + 1, mstate, vstate)) {
4581                         regs[rd] = NULL;
4582                         break;
4583                 }
4584 
4585                 if (!DTRACE_INSCRATCH(mstate, jsonlen + 1 + elemlen + 1)) {
4586                         DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4587                         regs[rd] = NULL;
4588                         break;
4589                 }
4590 
4591                 /*
4592                  * Read the element selector and split it up into a packed list
4593                  * of strings.
4594                  */
4595                 for (cur = elem; cur < elem + elemlen; cur++) {
4596                         char cc = dtrace_load8(cur);
4597 
4598                         if (cur == elem && cc == '[') {
4599                                 /*
4600                                  * If the first element selector key is
4601                                  * actually an array index then ignore the
4602                                  * bracket.
4603                                  */
4604                                 continue;
4605                         }
4606 
4607                         if (cc == ']')
4608                                 continue;
4609 
4610                         if (cc == '.' || cc == '[') {
4611                                 nelems++;
4612                                 cc = '\0';
4613                         }
4614 
4615                         *ee++ = cc;
4616                 }
4617                 *ee++ = '\0';
4618 
4619                 if ((regs[rd] = (uintptr_t)dtrace_json(size, json, elemlist,
4620                     nelems, dest)) != NULL)
4621                         mstate->dtms_scratch_ptr += jsonlen + 1;
4622                 break;
4623         }
4624 
4625         case DIF_SUBR_TOUPPER:
4626         case DIF_SUBR_TOLOWER: {
4627                 uintptr_t s = tupregs[0].dttk_value;
4628                 uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
4629                 char *dest = (char *)mstate->dtms_scratch_ptr, c;
4630                 size_t len = dtrace_strlen((char *)s, size);
4631                 char lower, upper, convert;
4632                 int64_t i;
4633 
4634                 if (subr == DIF_SUBR_TOUPPER) {
4635                         lower = 'a';
4636                         upper = 'z';
4637                         convert = 'A';
4638                 } else {
4639                         lower = 'A';
4640                         upper = 'Z';
4641                         convert = 'a';
4642                 }
4643 
4644                 if (!dtrace_canload(s, len + 1, mstate, vstate)) {


4912 
4913                 for (;;) {
4914                         if (i >= size) {
4915                                 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4916                                 regs[rd] = NULL;
4917                                 break;
4918                         }
4919 
4920                         if ((d[i++] = dtrace_load8(s2++)) == '\0')
4921                                 break;
4922                 }
4923 
4924                 if (i < size) {
4925                         mstate->dtms_scratch_ptr += i;
4926                         regs[rd] = (uintptr_t)d;
4927                 }
4928 
4929                 break;
4930         }
4931 
4932         case DIF_SUBR_STRTOLL: {
4933                 uintptr_t s = tupregs[0].dttk_value;
4934                 uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
4935                 int base = 10;
4936 
4937                 if (nargs > 1) {
4938                         if ((base = tupregs[1].dttk_value) <= 1 ||
4939                             base > ('z' - 'a' + 1) + ('9' - '0' + 1)) {
4940                                 *flags |= CPU_DTRACE_ILLOP;
4941                                 break;
4942                         }
4943                 }
4944 
4945                 if (!dtrace_strcanload(s, size, mstate, vstate)) {
4946                         regs[rd] = INT64_MIN;
4947                         break;
4948                 }
4949 
4950                 regs[rd] = dtrace_strtoll((char *)s, base, size);
4951                 break;
4952         }
4953 
4954         case DIF_SUBR_LLTOSTR: {
4955                 int64_t i = (int64_t)tupregs[0].dttk_value;
4956                 uint64_t val, digit;
4957                 uint64_t size = 65;     /* enough room for 2^64 in binary */
4958                 char *end = (char *)mstate->dtms_scratch_ptr + size - 1;
4959                 int base = 10;
4960 
4961                 if (nargs > 1) {
4962                         if ((base = tupregs[1].dttk_value) <= 1 ||
4963                             base > ('z' - 'a' + 1) + ('9' - '0' + 1)) {
4964                                 *flags |= CPU_DTRACE_ILLOP;
4965                                 break;
4966                         }
4967                 }
4968 
4969                 val = (base == 10 && i < 0) ? i * -1 : i;
4970 
4971                 if (!DTRACE_INSCRATCH(mstate, size)) {
4972                         DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4973                         regs[rd] = NULL;


9463                 case DIF_OP_LDTAA:
9464                         err += efunc(pc, "illegal dynamic variable load\n");
9465                         break;
9466 
9467                 case DIF_OP_STTS:
9468                 case DIF_OP_STGAA:
9469                 case DIF_OP_STTAA:
9470                         err += efunc(pc, "illegal dynamic variable store\n");
9471                         break;
9472 
9473                 case DIF_OP_CALL:
9474                         if (subr == DIF_SUBR_ALLOCA ||
9475                             subr == DIF_SUBR_BCOPY ||
9476                             subr == DIF_SUBR_COPYIN ||
9477                             subr == DIF_SUBR_COPYINTO ||
9478                             subr == DIF_SUBR_COPYINSTR ||
9479                             subr == DIF_SUBR_INDEX ||
9480                             subr == DIF_SUBR_INET_NTOA ||
9481                             subr == DIF_SUBR_INET_NTOA6 ||
9482                             subr == DIF_SUBR_INET_NTOP ||
9483                             subr == DIF_SUBR_JSON ||
9484                             subr == DIF_SUBR_LLTOSTR ||
9485                             subr == DIF_SUBR_STRTOLL ||
9486                             subr == DIF_SUBR_RINDEX ||
9487                             subr == DIF_SUBR_STRCHR ||
9488                             subr == DIF_SUBR_STRJOIN ||
9489                             subr == DIF_SUBR_STRRCHR ||
9490                             subr == DIF_SUBR_STRSTR ||
9491                             subr == DIF_SUBR_HTONS ||
9492                             subr == DIF_SUBR_HTONL ||
9493                             subr == DIF_SUBR_HTONLL ||
9494                             subr == DIF_SUBR_NTOHS ||
9495                             subr == DIF_SUBR_NTOHL ||
9496                             subr == DIF_SUBR_NTOHLL)
9497                                 break;
9498 
9499                         err += efunc(pc, "invalid subr %u\n", subr);
9500                         break;
9501 
9502                 default:
9503                         err += efunc(pc, "invalid opcode %u\n",
9504                             DIF_INSTR_OP(instr));
9505                 }