Print this page
OS-1723 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 ↓ 765 lines elided ↑ open up ↑
 870  871  
 871  872                  sz = dtrace_strlen(src, strsize) + 1;
 872  873          } else {
 873  874                  sz = type->dtdt_size;
 874  875          }
 875  876  
 876  877          return (dtrace_canload((uintptr_t)src, sz, mstate, vstate));
 877  878  }
 878  879  
 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 +/*
 880  933   * Compare two strings using safe loads.
 881  934   */
 882  935  static int
 883  936  dtrace_strncmp(char *s1, char *s2, size_t limit)
 884  937  {
 885  938          uint8_t c1, c2;
 886  939          volatile uint16_t *flags;
 887  940  
 888  941          if (s1 == s2 || limit == 0)
 889  942                  return (0);
↓ open down ↓ 2456 lines elided ↑ open up ↑
3346 3399                          return (0);
3347 3400  
3348 3401                  return ((uint64_t)lwp->lwp_errno);
3349 3402          }
3350 3403          default:
3351 3404                  DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
3352 3405                  return (0);
3353 3406          }
3354 3407  }
3355 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 +
3356 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 +/*
3357 3867   * Emulate the execution of DTrace ID subroutines invoked by the call opcode.
3358 3868   * Notice that we don't bother validating the proper number of arguments or
3359 3869   * their types in the tuple stack.  This isn't needed because all argument
3360 3870   * interpretation is safe because of our load safety -- the worst that can
3361 3871   * happen is that a bogus program can obtain bogus results.
3362 3872   */
3363 3873  static void
3364 3874  dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
3365 3875      dtrace_key_t *tupregs, int nargs,
3366 3876      dtrace_mstate_t *mstate, dtrace_state_t *state)
↓ open down ↓ 679 lines elided ↑ open up ↑
4046 4556                                  break;
4047 4557                  }
4048 4558  
4049 4559                  d[i] = '\0';
4050 4560  
4051 4561                  mstate->dtms_scratch_ptr += size;
4052 4562                  regs[rd] = (uintptr_t)d;
4053 4563                  break;
4054 4564          }
4055 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 +
4056 4625          case DIF_SUBR_TOUPPER:
4057 4626          case DIF_SUBR_TOLOWER: {
4058 4627                  uintptr_t s = tupregs[0].dttk_value;
4059 4628                  uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
4060 4629                  char *dest = (char *)mstate->dtms_scratch_ptr, c;
4061 4630                  size_t len = dtrace_strlen((char *)s, size);
4062 4631                  char lower, upper, convert;
4063 4632                  int64_t i;
4064 4633  
4065 4634                  if (subr == DIF_SUBR_TOUPPER) {
↓ open down ↓ 287 lines elided ↑ open up ↑
4353 4922                  }
4354 4923  
4355 4924                  if (i < size) {
4356 4925                          mstate->dtms_scratch_ptr += i;
4357 4926                          regs[rd] = (uintptr_t)d;
4358 4927                  }
4359 4928  
4360 4929                  break;
4361 4930          }
4362 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 +
4363 4954          case DIF_SUBR_LLTOSTR: {
4364 4955                  int64_t i = (int64_t)tupregs[0].dttk_value;
4365 4956                  uint64_t val, digit;
4366 4957                  uint64_t size = 65;     /* enough room for 2^64 in binary */
4367 4958                  char *end = (char *)mstate->dtms_scratch_ptr + size - 1;
4368 4959                  int base = 10;
4369 4960  
4370 4961                  if (nargs > 1) {
4371 4962                          if ((base = tupregs[1].dttk_value) <= 1 ||
4372 4963                              base > ('z' - 'a' + 1) + ('9' - '0' + 1)) {
↓ open down ↓ 4509 lines elided ↑ open up ↑
8882 9473                  case DIF_OP_CALL:
8883 9474                          if (subr == DIF_SUBR_ALLOCA ||
8884 9475                              subr == DIF_SUBR_BCOPY ||
8885 9476                              subr == DIF_SUBR_COPYIN ||
8886 9477                              subr == DIF_SUBR_COPYINTO ||
8887 9478                              subr == DIF_SUBR_COPYINSTR ||
8888 9479                              subr == DIF_SUBR_INDEX ||
8889 9480                              subr == DIF_SUBR_INET_NTOA ||
8890 9481                              subr == DIF_SUBR_INET_NTOA6 ||
8891 9482                              subr == DIF_SUBR_INET_NTOP ||
     9483 +                            subr == DIF_SUBR_JSON ||
8892 9484                              subr == DIF_SUBR_LLTOSTR ||
     9485 +                            subr == DIF_SUBR_STRTOLL ||
8893 9486                              subr == DIF_SUBR_RINDEX ||
8894 9487                              subr == DIF_SUBR_STRCHR ||
8895 9488                              subr == DIF_SUBR_STRJOIN ||
8896 9489                              subr == DIF_SUBR_STRRCHR ||
8897 9490                              subr == DIF_SUBR_STRSTR ||
8898 9491                              subr == DIF_SUBR_HTONS ||
8899 9492                              subr == DIF_SUBR_HTONL ||
8900 9493                              subr == DIF_SUBR_HTONLL ||
8901 9494                              subr == DIF_SUBR_NTOHS ||
8902 9495                              subr == DIF_SUBR_NTOHL ||
↓ open down ↓ 7394 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX