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

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/dtrace/dtrace.c
          +++ new/usr/src/uts/common/dtrace/dtrace.c
↓ open down ↓ 84 lines elided ↑ open up ↑
  85   85  #include <sys/priv_impl.h>
  86   86  #include <sys/policy.h>
  87   87  #include <sys/cred_impl.h>
  88   88  #include <sys/procfs_isa.h>
  89   89  #include <sys/taskq.h>
  90   90  #include <sys/mkdev.h>
  91   91  #include <sys/kdi.h>
  92   92  #include <sys/zone.h>
  93   93  #include <sys/socket.h>
  94   94  #include <netinet/in.h>
       95 +#include "strtolctype.h"
  95   96  
  96   97  /*
  97   98   * DTrace Tunable Variables
  98   99   *
  99  100   * The following variables may be tuned by adding a line to /etc/system that
 100  101   * includes both the name of the DTrace module ("dtrace") and the name of the
 101  102   * variable.  For example:
 102  103   *
 103  104   *   set dtrace:dtrace_destructive_disallow = 1
 104  105   *
↓ open down ↓ 747 lines elided ↑ open up ↑
 852  853          if (type->dtdt_kind == DIF_TYPE_STRING)
 853  854                  sz = dtrace_strlen(src,
 854  855                      vstate->dtvs_state->dts_options[DTRACEOPT_STRSIZE]) + 1;
 855  856          else
 856  857                  sz = type->dtdt_size;
 857  858  
 858  859          return (dtrace_canload((uintptr_t)src, sz, mstate, vstate));
 859  860  }
 860  861  
 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 +/*
 862  915   * Compare two strings using safe loads.
 863  916   */
 864  917  static int
 865  918  dtrace_strncmp(char *s1, char *s2, size_t limit)
 866  919  {
 867  920          uint8_t c1, c2;
 868  921          volatile uint16_t *flags;
 869  922  
 870  923          if (s1 == s2 || limit == 0)
 871  924                  return (0);
↓ open down ↓ 2456 lines elided ↑ open up ↑
3328 3381                          return (0);
3329 3382  
3330 3383                  return ((uint64_t)lwp->lwp_errno);
3331 3384          }
3332 3385          default:
3333 3386                  DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
3334 3387                  return (0);
3335 3388          }
3336 3389  }
3337 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 +
3338 3848  /*
3339 3849   * Emulate the execution of DTrace ID subroutines invoked by the call opcode.
3340 3850   * Notice that we don't bother validating the proper number of arguments or
3341 3851   * their types in the tuple stack.  This isn't needed because all argument
3342 3852   * interpretation is safe because of our load safety -- the worst that can
3343 3853   * happen is that a bogus program can obtain bogus results.
3344 3854   */
3345 3855  static void
3346 3856  dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
3347 3857      dtrace_key_t *tupregs, int nargs,
↓ open down ↓ 680 lines elided ↑ open up ↑
4028 4538                                  break;
4029 4539                  }
4030 4540  
4031 4541                  d[i] = '\0';
4032 4542  
4033 4543                  mstate->dtms_scratch_ptr += size;
4034 4544                  regs[rd] = (uintptr_t)d;
4035 4545                  break;
4036 4546          }
4037 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 +
4038 4607          case DIF_SUBR_TOUPPER:
4039 4608          case DIF_SUBR_TOLOWER: {
4040 4609                  uintptr_t s = tupregs[0].dttk_value;
4041 4610                  uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
4042 4611                  char *dest = (char *)mstate->dtms_scratch_ptr, c;
4043 4612                  size_t len = dtrace_strlen((char *)s, size);
4044 4613                  char lower, upper, convert;
4045 4614                  int64_t i;
4046 4615  
4047 4616                  if (subr == DIF_SUBR_TOUPPER) {
↓ open down ↓ 287 lines elided ↑ open up ↑
4335 4904                  }
4336 4905  
4337 4906                  if (i < size) {
4338 4907                          mstate->dtms_scratch_ptr += i;
4339 4908                          regs[rd] = (uintptr_t)d;
4340 4909                  }
4341 4910  
4342 4911                  break;
4343 4912          }
4344 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 +
4345 4936          case DIF_SUBR_LLTOSTR: {
4346 4937                  int64_t i = (int64_t)tupregs[0].dttk_value;
4347 4938                  uint64_t val, digit;
4348 4939                  uint64_t size = 65;     /* enough room for 2^64 in binary */
4349 4940                  char *end = (char *)mstate->dtms_scratch_ptr + size - 1;
4350 4941                  int base = 10;
4351 4942  
4352 4943                  if (nargs > 1) {
4353 4944                          if ((base = tupregs[1].dttk_value) <= 1 ||
4354 4945                              base > ('z' - 'a' + 1) + ('9' - '0' + 1)) {
↓ open down ↓ 4499 lines elided ↑ open up ↑
8854 9445                  case DIF_OP_CALL:
8855 9446                          if (subr == DIF_SUBR_ALLOCA ||
8856 9447                              subr == DIF_SUBR_BCOPY ||
8857 9448                              subr == DIF_SUBR_COPYIN ||
8858 9449                              subr == DIF_SUBR_COPYINTO ||
8859 9450                              subr == DIF_SUBR_COPYINSTR ||
8860 9451                              subr == DIF_SUBR_INDEX ||
8861 9452                              subr == DIF_SUBR_INET_NTOA ||
8862 9453                              subr == DIF_SUBR_INET_NTOA6 ||
8863 9454                              subr == DIF_SUBR_INET_NTOP ||
     9455 +                            subr == DIF_SUBR_JSON ||
8864 9456                              subr == DIF_SUBR_LLTOSTR ||
     9457 +                            subr == DIF_SUBR_STRTOLL ||
8865 9458                              subr == DIF_SUBR_RINDEX ||
8866 9459                              subr == DIF_SUBR_STRCHR ||
8867 9460                              subr == DIF_SUBR_STRJOIN ||
8868 9461                              subr == DIF_SUBR_STRRCHR ||
8869 9462                              subr == DIF_SUBR_STRSTR ||
8870 9463                              subr == DIF_SUBR_HTONS ||
8871 9464                              subr == DIF_SUBR_HTONL ||
8872 9465                              subr == DIF_SUBR_HTONLL ||
8873 9466                              subr == DIF_SUBR_NTOHS ||
8874 9467                              subr == DIF_SUBR_NTOHL ||
↓ open down ↓ 7378 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX