Print this page
4477 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.


 842         size_t sz;
 843         ASSERT(type->dtdt_flags & DIF_TF_BYREF);
 844 
 845         /*
 846          * If we hold the privilege to read from kernel memory, then
 847          * everything is readable.
 848          */
 849         if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) != 0)
 850                 return (1);
 851 
 852         if (type->dtdt_kind == DIF_TYPE_STRING)
 853                 sz = dtrace_strlen(src,
 854                     vstate->dtvs_state->dts_options[DTRACEOPT_STRSIZE]) + 1;
 855         else
 856                 sz = type->dtdt_size;
 857 
 858         return (dtrace_canload((uintptr_t)src, sz, mstate, vstate));
 859 }
 860 
 861 /*




















































 862  * Compare two strings using safe loads.
 863  */
 864 static int
 865 dtrace_strncmp(char *s1, char *s2, size_t limit)
 866 {
 867         uint8_t c1, c2;
 868         volatile uint16_t *flags;
 869 
 870         if (s1 == s2 || limit == 0)
 871                 return (0);
 872 
 873         flags = (volatile uint16_t *)&cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
 874 
 875         do {
 876                 if (s1 == NULL) {
 877                         c1 = '\0';
 878                 } else {
 879                         c1 = dtrace_load8((uintptr_t)s1++);
 880                 }
 881 


3318                 if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU))
3319                         return (0);
3320 
3321                 /*
3322                  * It is always safe to dereference one's own t_lwp pointer in
3323                  * the event that this pointer is non-NULL.  (This is true
3324                  * because threads and lwps don't clean up their own state --
3325                  * they leave that task to whomever reaps them.)
3326                  */
3327                 if ((lwp = curthread->t_lwp) == NULL)
3328                         return (0);
3329 
3330                 return ((uint64_t)lwp->lwp_errno);
3331         }
3332         default:
3333                 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
3334                 return (0);
3335         }
3336 }
3337 









































































































































































































































































































































































































































































3338 /*
3339  * Emulate the execution of DTrace ID subroutines invoked by the call opcode.
3340  * Notice that we don't bother validating the proper number of arguments or
3341  * their types in the tuple stack.  This isn't needed because all argument
3342  * interpretation is safe because of our load safety -- the worst that can
3343  * happen is that a bogus program can obtain bogus results.
3344  */
3345 static void
3346 dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
3347     dtrace_key_t *tupregs, int nargs,
3348     dtrace_mstate_t *mstate, dtrace_state_t *state)
3349 {
3350         volatile uint16_t *flags = &cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
3351         volatile uintptr_t *illval = &cpu_core[CPU->cpu_id].cpuc_dtrace_illval;
3352         dtrace_vstate_t *vstate = &state->dts_vstate;
3353 
3354         union {
3355                 mutex_impl_t mi;
3356                 uint64_t mx;
3357         } m;


4018                 if (index >= len || index < 0) {
4019                         remaining = 0;
4020                 } else if (remaining < 0) {
4021                         remaining += len - index;
4022                 } else if (index + remaining > size) {
4023                         remaining = size - index;
4024                 }
4025 
4026                 for (i = 0; i < remaining; i++) {
4027                         if ((d[i] = dtrace_load8(s + index + i)) == '\0')
4028                                 break;
4029                 }
4030 
4031                 d[i] = '\0';
4032 
4033                 mstate->dtms_scratch_ptr += size;
4034                 regs[rd] = (uintptr_t)d;
4035                 break;
4036         }
4037 



























































4038         case DIF_SUBR_TOUPPER:
4039         case DIF_SUBR_TOLOWER: {
4040                 uintptr_t s = tupregs[0].dttk_value;
4041                 uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
4042                 char *dest = (char *)mstate->dtms_scratch_ptr, c;
4043                 size_t len = dtrace_strlen((char *)s, size);
4044                 char lower, upper, convert;
4045                 int64_t i;
4046 
4047                 if (subr == DIF_SUBR_TOUPPER) {
4048                         lower = 'a';
4049                         upper = 'z';
4050                         convert = 'A';
4051                 } else {
4052                         lower = 'A';
4053                         upper = 'Z';
4054                         convert = 'a';
4055                 }
4056 
4057                 if (!dtrace_canload(s, len + 1, mstate, vstate)) {


4325 
4326                 for (;;) {
4327                         if (i >= size) {
4328                                 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4329                                 regs[rd] = NULL;
4330                                 break;
4331                         }
4332 
4333                         if ((d[i++] = dtrace_load8(s2++)) == '\0')
4334                                 break;
4335                 }
4336 
4337                 if (i < size) {
4338                         mstate->dtms_scratch_ptr += i;
4339                         regs[rd] = (uintptr_t)d;
4340                 }
4341 
4342                 break;
4343         }
4344 






















4345         case DIF_SUBR_LLTOSTR: {
4346                 int64_t i = (int64_t)tupregs[0].dttk_value;
4347                 uint64_t val, digit;
4348                 uint64_t size = 65;     /* enough room for 2^64 in binary */
4349                 char *end = (char *)mstate->dtms_scratch_ptr + size - 1;
4350                 int base = 10;
4351 
4352                 if (nargs > 1) {
4353                         if ((base = tupregs[1].dttk_value) <= 1 ||
4354                             base > ('z' - 'a' + 1) + ('9' - '0' + 1)) {
4355                                 *flags |= CPU_DTRACE_ILLOP;
4356                                 break;
4357                         }
4358                 }
4359 
4360                 val = (base == 10 && i < 0) ? i * -1 : i;
4361 
4362                 if (!DTRACE_INSCRATCH(mstate, size)) {
4363                         DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4364                         regs[rd] = NULL;


8844                 case DIF_OP_LDTAA:
8845                         err += efunc(pc, "illegal dynamic variable load\n");
8846                         break;
8847 
8848                 case DIF_OP_STTS:
8849                 case DIF_OP_STGAA:
8850                 case DIF_OP_STTAA:
8851                         err += efunc(pc, "illegal dynamic variable store\n");
8852                         break;
8853 
8854                 case DIF_OP_CALL:
8855                         if (subr == DIF_SUBR_ALLOCA ||
8856                             subr == DIF_SUBR_BCOPY ||
8857                             subr == DIF_SUBR_COPYIN ||
8858                             subr == DIF_SUBR_COPYINTO ||
8859                             subr == DIF_SUBR_COPYINSTR ||
8860                             subr == DIF_SUBR_INDEX ||
8861                             subr == DIF_SUBR_INET_NTOA ||
8862                             subr == DIF_SUBR_INET_NTOA6 ||
8863                             subr == DIF_SUBR_INET_NTOP ||

8864                             subr == DIF_SUBR_LLTOSTR ||

8865                             subr == DIF_SUBR_RINDEX ||
8866                             subr == DIF_SUBR_STRCHR ||
8867                             subr == DIF_SUBR_STRJOIN ||
8868                             subr == DIF_SUBR_STRRCHR ||
8869                             subr == DIF_SUBR_STRSTR ||
8870                             subr == DIF_SUBR_HTONS ||
8871                             subr == DIF_SUBR_HTONL ||
8872                             subr == DIF_SUBR_HTONLL ||
8873                             subr == DIF_SUBR_NTOHS ||
8874                             subr == DIF_SUBR_NTOHL ||
8875                             subr == DIF_SUBR_NTOHLL)
8876                                 break;
8877 
8878                         err += efunc(pc, "invalid subr %u\n", subr);
8879                         break;
8880 
8881                 default:
8882                         err += efunc(pc, "invalid opcode %u\n",
8883                             DIF_INSTR_OP(instr));
8884                 }




  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.


 843         size_t sz;
 844         ASSERT(type->dtdt_flags & DIF_TF_BYREF);
 845 
 846         /*
 847          * If we hold the privilege to read from kernel memory, then
 848          * everything is readable.
 849          */
 850         if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) != 0)
 851                 return (1);
 852 
 853         if (type->dtdt_kind == DIF_TYPE_STRING)
 854                 sz = dtrace_strlen(src,
 855                     vstate->dtvs_state->dts_options[DTRACEOPT_STRSIZE]) + 1;
 856         else
 857                 sz = type->dtdt_size;
 858 
 859         return (dtrace_canload((uintptr_t)src, sz, mstate, vstate));
 860 }
 861 
 862 /*
 863  * Convert a string to a signed integer using safe loads.
 864  *
 865  * NOTE: This function uses various macros from strtolctype.h to manipulate
 866  * digit values, etc -- these have all been checked to ensure they make
 867  * no additional function calls.
 868  */
 869 static int64_t
 870 dtrace_strtoll(char *input, int base, size_t limit)
 871 {
 872         uintptr_t pos = (uintptr_t)input;
 873         int64_t val = 0;
 874         int x;
 875         boolean_t neg = B_FALSE;
 876         char c, cc, ccc;
 877         uintptr_t end = pos + limit;
 878 
 879         /*
 880          * Consume any whitespace preceding digits.
 881          */
 882         while ((c = dtrace_load8(pos)) == ' ' || c == '\t')
 883                 pos++;
 884 
 885         /*
 886          * Handle an explicit sign if one is present.
 887          */
 888         if (c == '-' || c == '+') {
 889                 if (c == '-')
 890                         neg = B_TRUE;
 891                 c = dtrace_load8(++pos);
 892         }
 893 
 894         /*
 895          * Check for an explicit hexadecimal prefix ("0x" or "0X") and skip it
 896          * if present.
 897          */
 898         if (base == 16 && c == '0' && ((cc = dtrace_load8(pos + 1)) == 'x' ||
 899             cc == 'X') && isxdigit(ccc = dtrace_load8(pos + 2))) {
 900                 pos += 2;
 901                 c = ccc;
 902         }
 903 
 904         /*
 905          * Read in contiguous digits until the first non-digit character.
 906          */
 907         for (; pos < end && c != '\0' && lisalnum(c) && (x = DIGIT(c)) < base;
 908             c = dtrace_load8(++pos))
 909                 val = val * base + x;
 910 
 911         return (neg ? -val : val);
 912 }
 913 
 914 /*
 915  * Compare two strings using safe loads.
 916  */
 917 static int
 918 dtrace_strncmp(char *s1, char *s2, size_t limit)
 919 {
 920         uint8_t c1, c2;
 921         volatile uint16_t *flags;
 922 
 923         if (s1 == s2 || limit == 0)
 924                 return (0);
 925 
 926         flags = (volatile uint16_t *)&cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
 927 
 928         do {
 929                 if (s1 == NULL) {
 930                         c1 = '\0';
 931                 } else {
 932                         c1 = dtrace_load8((uintptr_t)s1++);
 933                 }
 934 


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


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


4894 
4895                 for (;;) {
4896                         if (i >= size) {
4897                                 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4898                                 regs[rd] = NULL;
4899                                 break;
4900                         }
4901 
4902                         if ((d[i++] = dtrace_load8(s2++)) == '\0')
4903                                 break;
4904                 }
4905 
4906                 if (i < size) {
4907                         mstate->dtms_scratch_ptr += i;
4908                         regs[rd] = (uintptr_t)d;
4909                 }
4910 
4911                 break;
4912         }
4913 
4914         case DIF_SUBR_STRTOLL: {
4915                 uintptr_t s = tupregs[0].dttk_value;
4916                 uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
4917                 int base = 10;
4918 
4919                 if (nargs > 1) {
4920                         if ((base = tupregs[1].dttk_value) <= 1 ||
4921                             base > ('z' - 'a' + 1) + ('9' - '0' + 1)) {
4922                                 *flags |= CPU_DTRACE_ILLOP;
4923                                 break;
4924                         }
4925                 }
4926 
4927                 if (!dtrace_strcanload(s, size, mstate, vstate)) {
4928                         regs[rd] = INT64_MIN;
4929                         break;
4930                 }
4931 
4932                 regs[rd] = dtrace_strtoll((char *)s, base, size);
4933                 break;
4934         }
4935 
4936         case DIF_SUBR_LLTOSTR: {
4937                 int64_t i = (int64_t)tupregs[0].dttk_value;
4938                 uint64_t val, digit;
4939                 uint64_t size = 65;     /* enough room for 2^64 in binary */
4940                 char *end = (char *)mstate->dtms_scratch_ptr + size - 1;
4941                 int base = 10;
4942 
4943                 if (nargs > 1) {
4944                         if ((base = tupregs[1].dttk_value) <= 1 ||
4945                             base > ('z' - 'a' + 1) + ('9' - '0' + 1)) {
4946                                 *flags |= CPU_DTRACE_ILLOP;
4947                                 break;
4948                         }
4949                 }
4950 
4951                 val = (base == 10 && i < 0) ? i * -1 : i;
4952 
4953                 if (!DTRACE_INSCRATCH(mstate, size)) {
4954                         DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4955                         regs[rd] = NULL;


9435                 case DIF_OP_LDTAA:
9436                         err += efunc(pc, "illegal dynamic variable load\n");
9437                         break;
9438 
9439                 case DIF_OP_STTS:
9440                 case DIF_OP_STGAA:
9441                 case DIF_OP_STTAA:
9442                         err += efunc(pc, "illegal dynamic variable store\n");
9443                         break;
9444 
9445                 case DIF_OP_CALL:
9446                         if (subr == DIF_SUBR_ALLOCA ||
9447                             subr == DIF_SUBR_BCOPY ||
9448                             subr == DIF_SUBR_COPYIN ||
9449                             subr == DIF_SUBR_COPYINTO ||
9450                             subr == DIF_SUBR_COPYINSTR ||
9451                             subr == DIF_SUBR_INDEX ||
9452                             subr == DIF_SUBR_INET_NTOA ||
9453                             subr == DIF_SUBR_INET_NTOA6 ||
9454                             subr == DIF_SUBR_INET_NTOP ||
9455                             subr == DIF_SUBR_JSON ||
9456                             subr == DIF_SUBR_LLTOSTR ||
9457                             subr == DIF_SUBR_STRTOLL ||
9458                             subr == DIF_SUBR_RINDEX ||
9459                             subr == DIF_SUBR_STRCHR ||
9460                             subr == DIF_SUBR_STRJOIN ||
9461                             subr == DIF_SUBR_STRRCHR ||
9462                             subr == DIF_SUBR_STRSTR ||
9463                             subr == DIF_SUBR_HTONS ||
9464                             subr == DIF_SUBR_HTONL ||
9465                             subr == DIF_SUBR_HTONLL ||
9466                             subr == DIF_SUBR_NTOHS ||
9467                             subr == DIF_SUBR_NTOHL ||
9468                             subr == DIF_SUBR_NTOHLL)
9469                                 break;
9470 
9471                         err += efunc(pc, "invalid subr %u\n", subr);
9472                         break;
9473 
9474                 default:
9475                         err += efunc(pc, "invalid opcode %u\n",
9476                             DIF_INSTR_OP(instr));
9477                 }