862 strsize = state->dts_options[DTRACEOPT_STRSIZE];
863 } else {
864 /*
865 * In helper context, we have a NULL state; fall back
866 * to using the system-wide default for the string size
867 * in this case.
868 */
869 strsize = dtrace_strsize_default;
870 }
871
872 sz = dtrace_strlen(src, strsize) + 1;
873 } else {
874 sz = type->dtdt_size;
875 }
876
877 return (dtrace_canload((uintptr_t)src, sz, mstate, vstate));
878 }
879
880 /*
881 * Convert a string to a signed integer using safe loads.
882 */
883 static int64_t
884 dtrace_strtoll(char *input, int base, size_t limit)
885 {
886 uintptr_t pos = (uintptr_t)input;
887 int64_t val = 0;
888 int x;
889 boolean_t neg = B_FALSE;
890 char c, cc, ccc;
891 uintptr_t end = pos + limit;
892
893 /* eat whitespace */
894 while ((c = dtrace_load8(pos)) == ' ' || c == '\t')
895 pos++;
896
897 /* sign? */
898 if (c == '-' || c == '+') {
899 if (c == '-')
900 neg = B_TRUE;
901 c = dtrace_load8(++pos);
902 }
903
904 /* hex prefix? */
905 if (base == 16 && c == '0' && ((cc = dtrace_load8(pos + 1)) == 'x' ||
906 cc == 'X') && isxdigit(ccc = dtrace_load8(pos + 2))) {
907 pos += 2; /* skip over leading "0x" or "0X" */
908 c = ccc;
909 }
910
911 /* read in digits */
912 for (; pos < end && c != '\0' && lisalnum(c) && (x = DIGIT(c)) < base;
913 c = dtrace_load8(++pos))
914 val = val * base + x;
915
916 return (neg ? -val : val);
917 }
918
919 /*
920 * Compare two strings using safe loads.
921 */
922 static int
923 dtrace_strncmp(char *s1, char *s2, size_t limit)
924 {
925 uint8_t c1, c2;
926 volatile uint16_t *flags;
927
928 if (s1 == s2 || limit == 0)
929 return (0);
930
931 flags = (volatile uint16_t *)&cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
3377 return (0);
3378
3379 /*
3380 * It is always safe to dereference one's own t_lwp pointer in
3381 * the event that this pointer is non-NULL. (This is true
3382 * because threads and lwps don't clean up their own state --
3383 * they leave that task to whomever reaps them.)
3384 */
3385 if ((lwp = curthread->t_lwp) == NULL)
3386 return (0);
3387
3388 return ((uint64_t)lwp->lwp_errno);
3389 }
3390 default:
3391 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
3392 return (0);
3393 }
3394 }
3395
3396
3397 typedef enum json_state {
3398 JSON_REST = 1,
3399 JSON_OBJECT,
3400 JSON_STRING,
3401 JSON_STRING_ESCAPE,
3402 JSON_STRING_ESCAPE_UNICODE,
3403 JSON_COLON,
3404 JSON_COMMA,
3405 JSON_VALUE,
3406 JSON_IDENTIFIER,
3407 JSON_NUMBER,
3408 JSON_NUMBER_FRAC,
3409 JSON_NUMBER_EXP,
3410 JSON_COLLECT_OBJECT
3411 } json_state_t;
3412
3413 /*
3414 * This function possesses just enough knowledge about JSON to extract a single
3415 * value from a JSON string and store it in the scratch buffer. It is able
3416 * to extract nested object values, and members of arrays by index.
3417 *
3418 * elemlist is a list of JSON keys, stored as packed NUL-terminated strings, to
3419 * be looked up as we descend into the object tree. e.g.
3420 *
3421 * foo[0].bar.baz[32] --> "foo" NUL "0" NUL "bar" NUL "baz" NUL "32" NUL
3422 * with nelems = 5.
3423 */
3424 static char *
3425 dtrace_json(uint64_t size, uintptr_t json, char *elemlist, int nelems,
3426 char *dest)
3427 {
3428 json_state_t state = JSON_REST;
3429 uint64_t i;
3430 int64_t array_elem = INT64_MIN;
3431 int64_t array_pos = 0;
3432 uint8_t escape_unicount = 0;
3433 boolean_t string_is_key = B_FALSE;
3434 boolean_t collect_object = B_FALSE;
3435 boolean_t found_key = B_FALSE;
3436 boolean_t in_array = B_FALSE;
3437 uint8_t braces = 0, brackets = 0;
3438 char *elem = elemlist;
3439 char *dd = dest;
3440 uintptr_t cur;
3441
3442 for (cur = json; cur < json + size; cur++) {
3443 char cc = dtrace_load8(cur);
3444 if (cc == '\0' || braces > 250)
3445 return (NULL);
3446
3447 switch (state) {
3448 case JSON_REST:
3449 if (cc == ' ' || cc == '\t' || cc == '\n' || cc == '\r')
3450 break; /* eat whitespace */
3451
3452 if (cc == '{') {
3453 state = JSON_OBJECT;
3454 break;
3455 }
3456
3457 if (cc == '[') {
3458 in_array = B_TRUE;
3459 array_pos = 0;
3460 array_elem = dtrace_strtoll(elem, 10, size);
3461 found_key = !!(array_elem == 0);
3462 state = JSON_VALUE;
3463 break;
3464 }
3465
3466 /* ERROR: expected object or array */
3467 return (NULL);
3468 case JSON_OBJECT:
3469 if (cc == ' ' || cc == '\t' || cc == '\n' || cc == '\r')
3470 break; /* eat whitespace */
3471
3472 if (cc == '"') {
3473 state = JSON_STRING;
3474 string_is_key = B_TRUE;
3475 break;
3476 }
3477
3478 /* ERROR: key not found! */
3479 return (NULL);
3480 case JSON_STRING:
3481 if (cc == '\\') {
3482 *dd++ = '\\';
3483 state = JSON_STRING_ESCAPE;
3484 break;
3485 }
3486
3487 if (cc == '"') {
3488 if (collect_object) {
3489 /*
3490 * We don't reset the dest here, as
3491 * the string is part of a larger
3492 * object being collected.
3493 */
3494 *dd++ = cc;
3495 collect_object = B_FALSE;
3496 state = JSON_COLLECT_OBJECT;
3497 break;
3498 }
3499 *dd = '\0';
3500 dd = dest; /* reset string buffer */
3501 if (string_is_key) {
3502 if (dtrace_strncmp(dest, elem,
3503 size) == 0)
3504 found_key = B_TRUE;
3505 } else if (found_key) {
3506 if (nelems > 1) {
3507 /*
3508 * We expected an object, not
3509 * this string.
3510 */
3511 return (NULL);
3512 }
3513 return (dest);
3514 }
3515 state = string_is_key ? JSON_COLON :
3516 JSON_COMMA;
3517 string_is_key = B_FALSE;
3518 break;
3519 }
3520
3521 *dd++ = cc;
3522 break;
3523 case JSON_STRING_ESCAPE:
3524 *dd++ = cc;
3525 if (cc == 'u') {
3526 escape_unicount = 0;
3527 state = JSON_STRING_ESCAPE_UNICODE;
3528 } else {
3529 state = JSON_STRING;
3530 }
3531 break;
3532 case JSON_STRING_ESCAPE_UNICODE:
3533 if (!isxdigit(cc))
3534 /* ERROR: unvalid unicode escape */
3535 return (NULL);
3536
3537 *dd++ = cc;
3538 if (++escape_unicount == 4)
3539 state = JSON_STRING;
3540 break;
3541 case JSON_COLON:
3542 if (cc == ' ' || cc == '\t' || cc == '\n' || cc == '\r')
3543 break; /* eat whitespace */
3544
3545 if (cc == ':') {
3546 state = JSON_VALUE;
3547 break;
3548 }
3549
3550 /* ERROR: expected colon */
3551 return (NULL);
3552 case JSON_COMMA:
3553 if (cc == ' ' || cc == '\t' || cc == '\n' || cc == '\r')
3554 break; /* eat whitespace */
3555
3556 if (cc == ',') {
3557 if (in_array) {
3558 state = JSON_VALUE;
3559 if (++array_pos == array_elem)
3560 found_key = B_TRUE;
3561 } else {
3562 state = JSON_OBJECT;
3563 }
3564 break;
3565 }
3566
3567 /* ERROR: key not found or expected comma */
3568 return (NULL);
3569 case JSON_IDENTIFIER:
3570 if (cc >= 'a' && cc <= 'z') {
3571 *dd++ = cc;
3572 break;
3573 }
3574
3575 *dd = '\0';
3576 dd = dest; /* reset string buffer */
3577
3578 if (dtrace_strncmp(dest, "true", 5) == 0 ||
3579 dtrace_strncmp(dest, "false", 6) == 0 ||
3580 dtrace_strncmp(dest, "null", 5) == 0) {
3581 if (found_key) {
3582 if (nelems > 1) {
3583 /*
3584 * We expected an object, not
3585 * this identifier.
3586 */
3587 return (NULL);
3588 }
3589 return (dest);
3590 } else {
3591 cur--;
3592 state = JSON_COMMA;
3593 break;
3594 }
3595 }
3596
3597 /* ERROR: unexpected identifier */
3598 return (NULL);
3599 case JSON_NUMBER:
3600 if (cc == '.') {
3601 *dd++ = cc;
3602 state = JSON_NUMBER_FRAC;
3603 break;
3604 }
3605
3606 if (cc == 'x' || cc == 'X')
3607 /* ERROR: spec explicitly excludes hex */
3608 return (NULL);
3609
3610 /* FALLTHRU */
3611 case JSON_NUMBER_FRAC:
3612 if (cc == 'e' || cc == 'E') {
3613 *dd++ = cc;
3614 state = JSON_NUMBER_EXP;
3615 break;
3616 }
3617
3618 if (cc == '+' || cc == '-') {
3619 /*
3620 * ERROR: expect sign as part of exponent only
3621 */
3622 return (NULL);
3623 }
3624 /* FALLTHRU */
3625 case JSON_NUMBER_EXP:
3626 if ((cc >= '0' && cc <= '9') || cc == '+' ||
3627 cc == '-') {
3628 *dd++ = cc;
3629 break;
3630 }
3631
3632 *dd = '\0';
3633 dd = dest; /* reset string buffer */
3634 if (found_key) {
3635 if (nelems > 1) {
3636 /*
3637 * We expected an object, not this
3638 * number.
3639 */
3640 return (NULL);
3641 }
3642 return (dest);
3643 }
3644
3645 cur--;
3646 state = JSON_COMMA;
3647 break;
3648 case JSON_VALUE:
3649 if (cc == ' ' || cc == '\t' || cc == '\n' || cc == '\r')
3650 break; /* eat whitespace */
3651
3652 if (cc == '{' || cc == '[') {
3653 if (nelems > 1 && found_key) {
3654 in_array = !!(cc == '[');
3655 /*
3656 * If our element selector directs us
3657 * to descend into this nested object,
3658 * then move to the next selector
3659 * element in the list and restart the
3660 * state machine.
3661 */
3662 while (*elem != '\0')
3663 elem++;
3664 elem++; /* skip the inter-element NUL */
3665 nelems--;
3666 dd = dest;
3667 if (in_array) {
3668 state = JSON_VALUE;
3669 array_pos = 0;
3670 array_elem = dtrace_strtoll(
3671 elem, 10, size);
3672 found_key = !!(array_elem == 0);
3673 } else {
3674 found_key = B_FALSE;
3675 state = JSON_OBJECT;
3676 }
3677 break;
3678 }
3679
3680 /*
3681 * Otherwise, we wish to either skip this
3682 * nested object or return it in full.
3683 */
3684 if (cc == '[')
3685 brackets = 1;
3686 else
3687 braces = 1;
3688 *dd++ = cc;
3689 state = JSON_COLLECT_OBJECT;
3690 break;
3691 }
3692
3693 if (cc == '"') {
3694 state = JSON_STRING;
3695 break;
3696 }
3697
3698 if (cc >= 'a' && cc <= 'z') {
3699 /* Here we deal with true, false and null */
3700 *dd++ = cc;
3701 state = JSON_IDENTIFIER;
3702 break;
3703 }
3704
3705 if (cc == '-' || (cc >= '0' && cc <= '9')) {
3706 *dd++ = cc;
3707 state = JSON_NUMBER;
3708 break;
3709 }
3710
3711 /* ERROR: unexpected character */
3712 return (NULL);
3713 case JSON_COLLECT_OBJECT:
3714 if (cc == '\0')
3715 /* ERROR: unexpected end of input */
3716 return (NULL);
3717
3718 *dd++ = cc;
3719 if (cc == '"') {
3720 collect_object = B_TRUE;
3721 state = JSON_STRING;
3722 break;
3723 }
3724
3725 if (cc == ']') {
3726 if (brackets-- == 0) {
3727 /* ERROR: unbalanced brackets */
3728 return (NULL);
3729 }
3730 } else if (cc == '}') {
3731 if (braces-- == 0) {
3732 /* ERROR: unbalanced braces */
3733 return (NULL);
3734 }
3735 } else if (cc == '{') {
3736 braces++;
3737 } else if (cc == '[') {
3738 brackets++;
3739 }
3740
3741 if (brackets == 0 && braces == 0) {
3742 if (found_key) {
3743 *dd = '\0';
3744 return (dest);
3745 }
3746 dd = dest; /* reset string buffer */
3747 state = JSON_COMMA;
3748 }
3749 break;
3750 }
3751 }
3752 return (NULL);
3753 }
3754
3755 /*
3756 * Emulate the execution of DTrace ID subroutines invoked by the call opcode.
3757 * Notice that we don't bother validating the proper number of arguments or
3758 * their types in the tuple stack. This isn't needed because all argument
3759 * interpretation is safe because of our load safety -- the worst that can
3760 * happen is that a bogus program can obtain bogus results.
3761 */
3762 static void
3763 dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
3764 dtrace_key_t *tupregs, int nargs,
3765 dtrace_mstate_t *mstate, dtrace_state_t *state)
3766 {
3767 volatile uint16_t *flags = &cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
4467
4468 if (!dtrace_canload(json, jsonlen + 1, mstate, vstate) ||
4469 !dtrace_canload(elem, elemlen + 1, mstate, vstate)) {
4470 regs[rd] = NULL;
4471 break;
4472 }
4473
4474 if (!DTRACE_INSCRATCH(mstate, jsonlen + 1 + elemlen + 1)) {
4475 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4476 regs[rd] = NULL;
4477 break;
4478 }
4479
4480 /*
4481 * Read the element selector and split it up into a packed list
4482 * of strings.
4483 */
4484 for (cur = elem; cur < elem + elemlen; cur++) {
4485 char cc = dtrace_load8(cur);
4486
4487 if (cur == elem && cc == '[')
4488 /* first element selector may be an array */
4489 continue;
4490
4491 if (cc == ']')
4492 continue;
4493
4494 if (cc == '.' || cc == '[') {
4495 nelems++;
4496 cc = '\0';
4497 }
4498
4499 *ee++ = cc;
4500 }
4501 *ee++ = '\0';
4502
4503 if ((regs[rd] = (uintptr_t)dtrace_json(size, json, elemlist,
4504 nelems, dest)) != NULL)
4505 mstate->dtms_scratch_ptr += jsonlen + 1;
4506 break;
4507 }
4508
4509 case DIF_SUBR_TOUPPER:
|
862 strsize = state->dts_options[DTRACEOPT_STRSIZE];
863 } else {
864 /*
865 * In helper context, we have a NULL state; fall back
866 * to using the system-wide default for the string size
867 * in this case.
868 */
869 strsize = dtrace_strsize_default;
870 }
871
872 sz = dtrace_strlen(src, strsize) + 1;
873 } else {
874 sz = type->dtdt_size;
875 }
876
877 return (dtrace_canload((uintptr_t)src, sz, mstate, vstate));
878 }
879
880 /*
881 * Convert a string to a signed integer using safe loads.
882 *
883 * NOTE: This function uses various macros from strtolctype.h to manipulate
884 * digit values, etc -- these have all been checked to ensure they make
885 * no additional function calls.
886 */
887 static int64_t
888 dtrace_strtoll(char *input, int base, size_t limit)
889 {
890 uintptr_t pos = (uintptr_t)input;
891 int64_t val = 0;
892 int x;
893 boolean_t neg = B_FALSE;
894 char c, cc, ccc;
895 uintptr_t end = pos + limit;
896
897 /*
898 * Consume any whitespace preceding digits.
899 */
900 while ((c = dtrace_load8(pos)) == ' ' || c == '\t')
901 pos++;
902
903 /*
904 * Handle an explicit sign if one is present.
905 */
906 if (c == '-' || c == '+') {
907 if (c == '-')
908 neg = B_TRUE;
909 c = dtrace_load8(++pos);
910 }
911
912 /*
913 * Check for an explicit hexadecimal prefix ("0x" or "0X") and skip it
914 * if present.
915 */
916 if (base == 16 && c == '0' && ((cc = dtrace_load8(pos + 1)) == 'x' ||
917 cc == 'X') && isxdigit(ccc = dtrace_load8(pos + 2))) {
918 pos += 2;
919 c = ccc;
920 }
921
922 /*
923 * Read in contiguous digits until the first non-digit character.
924 */
925 for (; pos < end && c != '\0' && lisalnum(c) && (x = DIGIT(c)) < base;
926 c = dtrace_load8(++pos))
927 val = val * base + x;
928
929 return (neg ? -val : val);
930 }
931
932 /*
933 * Compare two strings using safe loads.
934 */
935 static int
936 dtrace_strncmp(char *s1, char *s2, size_t limit)
937 {
938 uint8_t c1, c2;
939 volatile uint16_t *flags;
940
941 if (s1 == s2 || limit == 0)
942 return (0);
943
944 flags = (volatile uint16_t *)&cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
3390 return (0);
3391
3392 /*
3393 * It is always safe to dereference one's own t_lwp pointer in
3394 * the event that this pointer is non-NULL. (This is true
3395 * because threads and lwps don't clean up their own state --
3396 * they leave that task to whomever reaps them.)
3397 */
3398 if ((lwp = curthread->t_lwp) == NULL)
3399 return (0);
3400
3401 return ((uint64_t)lwp->lwp_errno);
3402 }
3403 default:
3404 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
3405 return (0);
3406 }
3407 }
3408
3409
3410 typedef enum dtrace_json_state {
3411 DTRACE_JSON_REST = 1,
3412 DTRACE_JSON_OBJECT,
3413 DTRACE_JSON_STRING,
3414 DTRACE_JSON_STRING_ESCAPE,
3415 DTRACE_JSON_STRING_ESCAPE_UNICODE,
3416 DTRACE_JSON_COLON,
3417 DTRACE_JSON_COMMA,
3418 DTRACE_JSON_VALUE,
3419 DTRACE_JSON_IDENTIFIER,
3420 DTRACE_JSON_NUMBER,
3421 DTRACE_JSON_NUMBER_FRAC,
3422 DTRACE_JSON_NUMBER_EXP,
3423 DTRACE_JSON_COLLECT_OBJECT
3424 } dtrace_json_state_t;
3425
3426 /*
3427 * This function possesses just enough knowledge about JSON to extract a single
3428 * value from a JSON string and store it in the scratch buffer. It is able
3429 * to extract nested object values, and members of arrays by index.
3430 *
3431 * elemlist is a list of JSON keys, stored as packed NUL-terminated strings, to
3432 * be looked up as we descend into the object tree. e.g.
3433 *
3434 * foo[0].bar.baz[32] --> "foo" NUL "0" NUL "bar" NUL "baz" NUL "32" NUL
3435 * with nelems = 5.
3436 *
3437 * The run time of this function must be bounded above by strsize to limit the
3438 * amount of work done in probe context. As such, it is implemented as a
3439 * simple state machine, reading one character at a time using safe loads
3440 * until we find the requested element, hit a parsing error or run off the
3441 * end of the object or string.
3442 *
3443 * As there is no way for a subroutine to return an error without interrupting
3444 * clause execution, we simply return NULL in the event of a missing key or any
3445 * other error condition. Each NULL return in this function is commented with
3446 * the error condition it represents -- parsing or otherwise.
3447 *
3448 * The set of states for the state machine closely matches the JSON
3449 * specification (http://json.org/). Briefly:
3450 *
3451 * DTRACE_JSON_REST:
3452 * Skip whitespace until we find either a top-level Object, moving
3453 * to DTRACE_JSON_OBJECT; or an Array, moving to DTRACE_JSON_VALUE.
3454 *
3455 * DTRACE_JSON_OBJECT:
3456 * Locate the next key String in an Object. Sets a flag to denote
3457 * the next String as a key string and moves to DTRACE_JSON_STRING.
3458 *
3459 * DTRACE_JSON_COLON:
3460 * Skip whitespace until we find the colon that separates key Strings
3461 * from their values. Once found, move to DTRACE_JSON_VALUE.
3462 *
3463 * DTRACE_JSON_VALUE:
3464 * Detects the type of the next value (String, Number, Identifier, Object
3465 * or Array) and routes to the states that process that type. Here we also
3466 * deal with the element selector list if we are requested to traverse down
3467 * into the object tree.
3468 *
3469 * DTRACE_JSON_COMMA:
3470 * Skip whitespace until we find the comma that separates key-value pairs
3471 * in Objects (returning to DTRACE_JSON_OBJECT) or values in Arrays
3472 * (similarly DTRACE_JSON_VALUE). All following literal value processing
3473 * states return to this state at the end of their value, unless otherwise
3474 * noted.
3475 *
3476 * DTRACE_JSON_NUMBER, DTRACE_JSON_NUMBER_FRAC, DTRACE_JSON_NUMBER_EXP:
3477 * Processes a Number literal from the JSON, including any exponent
3478 * component that may be present. Numbers are returned as strings, which
3479 * may be passed to strtoll() if an integer is required.
3480 *
3481 * DTRACE_JSON_IDENTIFIER:
3482 * Processes a "true", "false" or "null" literal in the JSON.
3483 *
3484 * DTRACE_JSON_STRING, DTRACE_JSON_STRING_ESCAPE,
3485 * DTRACE_JSON_STRING_ESCAPE_UNICODE:
3486 * Processes a String literal from the JSON, whether the String denotes
3487 * a key, a value or part of a larger Object. Handles all escape sequences
3488 * present in the specification, including four-digit unicode characters,
3489 * but merely includes the escape sequence without converting it to the
3490 * actual escaped character. If the String is flagged as a key, we
3491 * move to DTRACE_JSON_COLON rather than DTRACE_JSON_COMMA.
3492 *
3493 * DTRACE_JSON_COLLECT_OBJECT:
3494 * This state collects an entire Object (or Array), correctly handling
3495 * embedded strings. If the full element selector list matches this nested
3496 * object, we return the Object in full as a string. If not, we use this
3497 * state to skip to the next value at this level and continue processing.
3498 *
3499 * NOTE: This function uses various macros from strtolctype.h to manipulate
3500 * digit values, etc -- these have all been checked to ensure they make
3501 * no additional function calls.
3502 */
3503 static char *
3504 dtrace_json(uint64_t size, uintptr_t json, char *elemlist, int nelems,
3505 char *dest)
3506 {
3507 dtrace_json_state_t state = DTRACE_JSON_REST;
3508 uint64_t i;
3509 int64_t array_elem = INT64_MIN;
3510 int64_t array_pos = 0;
3511 uint8_t escape_unicount = 0;
3512 boolean_t string_is_key = B_FALSE;
3513 boolean_t collect_object = B_FALSE;
3514 boolean_t found_key = B_FALSE;
3515 boolean_t in_array = B_FALSE;
3516 uint32_t braces = 0, brackets = 0;
3517 char *elem = elemlist;
3518 char *dd = dest;
3519 uintptr_t cur;
3520
3521 for (cur = json; cur < json + size; cur++) {
3522 char cc = dtrace_load8(cur);
3523 if (cc == '\0')
3524 return (NULL);
3525
3526 switch (state) {
3527 case DTRACE_JSON_REST:
3528 if (isspace(cc))
3529 break;
3530
3531 if (cc == '{') {
3532 state = DTRACE_JSON_OBJECT;
3533 break;
3534 }
3535
3536 if (cc == '[') {
3537 in_array = B_TRUE;
3538 array_pos = 0;
3539 array_elem = dtrace_strtoll(elem, 10, size);
3540 found_key = array_elem == 0 ? B_TRUE : B_FALSE;
3541 state = DTRACE_JSON_VALUE;
3542 break;
3543 }
3544
3545 /*
3546 * ERROR: expected to find a top-level object or array.
3547 */
3548 return (NULL);
3549 case DTRACE_JSON_OBJECT:
3550 if (isspace(cc))
3551 break;
3552
3553 if (cc == '"') {
3554 state = DTRACE_JSON_STRING;
3555 string_is_key = B_TRUE;
3556 break;
3557 }
3558
3559 /*
3560 * ERROR: either the object did not start with a key
3561 * string, or we've run off the end of the object
3562 * without finding the requested key.
3563 */
3564 return (NULL);
3565 case DTRACE_JSON_STRING:
3566 if (cc == '\\') {
3567 *dd++ = '\\';
3568 state = DTRACE_JSON_STRING_ESCAPE;
3569 break;
3570 }
3571
3572 if (cc == '"') {
3573 if (collect_object) {
3574 /*
3575 * We don't reset the dest here, as
3576 * the string is part of a larger
3577 * object being collected.
3578 */
3579 *dd++ = cc;
3580 collect_object = B_FALSE;
3581 state = DTRACE_JSON_COLLECT_OBJECT;
3582 break;
3583 }
3584 *dd = '\0';
3585 dd = dest; /* reset string buffer */
3586 if (string_is_key) {
3587 if (dtrace_strncmp(dest, elem,
3588 size) == 0)
3589 found_key = B_TRUE;
3590 } else if (found_key) {
3591 if (nelems > 1) {
3592 /*
3593 * We expected an object, not
3594 * this string.
3595 */
3596 return (NULL);
3597 }
3598 return (dest);
3599 }
3600 state = string_is_key ? DTRACE_JSON_COLON :
3601 DTRACE_JSON_COMMA;
3602 string_is_key = B_FALSE;
3603 break;
3604 }
3605
3606 *dd++ = cc;
3607 break;
3608 case DTRACE_JSON_STRING_ESCAPE:
3609 *dd++ = cc;
3610 if (cc == 'u') {
3611 escape_unicount = 0;
3612 state = DTRACE_JSON_STRING_ESCAPE_UNICODE;
3613 } else {
3614 state = DTRACE_JSON_STRING;
3615 }
3616 break;
3617 case DTRACE_JSON_STRING_ESCAPE_UNICODE:
3618 if (!isxdigit(cc)) {
3619 /*
3620 * ERROR: invalid unicode escape, expected
3621 * four valid hexidecimal digits.
3622 */
3623 return (NULL);
3624 }
3625
3626 *dd++ = cc;
3627 if (++escape_unicount == 4)
3628 state = DTRACE_JSON_STRING;
3629 break;
3630 case DTRACE_JSON_COLON:
3631 if (isspace(cc))
3632 break;
3633
3634 if (cc == ':') {
3635 state = DTRACE_JSON_VALUE;
3636 break;
3637 }
3638
3639 /*
3640 * ERROR: expected a colon.
3641 */
3642 return (NULL);
3643 case DTRACE_JSON_COMMA:
3644 if (isspace(cc))
3645 break;
3646
3647 if (cc == ',') {
3648 if (in_array) {
3649 state = DTRACE_JSON_VALUE;
3650 if (++array_pos == array_elem)
3651 found_key = B_TRUE;
3652 } else {
3653 state = DTRACE_JSON_OBJECT;
3654 }
3655 break;
3656 }
3657
3658 /*
3659 * ERROR: either we hit an unexpected character, or
3660 * we reached the end of the object or array without
3661 * finding the requested key.
3662 */
3663 return (NULL);
3664 case DTRACE_JSON_IDENTIFIER:
3665 if (islower(cc)) {
3666 *dd++ = cc;
3667 break;
3668 }
3669
3670 *dd = '\0';
3671 dd = dest; /* reset string buffer */
3672
3673 if (dtrace_strncmp(dest, "true", 5) == 0 ||
3674 dtrace_strncmp(dest, "false", 6) == 0 ||
3675 dtrace_strncmp(dest, "null", 5) == 0) {
3676 if (found_key) {
3677 if (nelems > 1) {
3678 /*
3679 * ERROR: We expected an object,
3680 * not this identifier.
3681 */
3682 return (NULL);
3683 }
3684 return (dest);
3685 } else {
3686 cur--;
3687 state = DTRACE_JSON_COMMA;
3688 break;
3689 }
3690 }
3691
3692 /*
3693 * ERROR: we did not recognise the identifier as one
3694 * of those in the JSON specification.
3695 */
3696 return (NULL);
3697 case DTRACE_JSON_NUMBER:
3698 if (cc == '.') {
3699 *dd++ = cc;
3700 state = DTRACE_JSON_NUMBER_FRAC;
3701 break;
3702 }
3703
3704 if (cc == 'x' || cc == 'X') {
3705 /*
3706 * ERROR: specification explicitly excludes
3707 * hexidecimal or octal numbers.
3708 */
3709 return (NULL);
3710 }
3711
3712 /* FALLTHRU */
3713 case DTRACE_JSON_NUMBER_FRAC:
3714 if (cc == 'e' || cc == 'E') {
3715 *dd++ = cc;
3716 state = DTRACE_JSON_NUMBER_EXP;
3717 break;
3718 }
3719
3720 if (cc == '+' || cc == '-') {
3721 /*
3722 * ERROR: expect sign as part of exponent only.
3723 */
3724 return (NULL);
3725 }
3726 /* FALLTHRU */
3727 case DTRACE_JSON_NUMBER_EXP:
3728 if (isdigit(cc) || cc == '+' || cc == '-') {
3729 *dd++ = cc;
3730 break;
3731 }
3732
3733 *dd = '\0';
3734 dd = dest; /* reset string buffer */
3735 if (found_key) {
3736 if (nelems > 1) {
3737 /*
3738 * ERROR: We expected an object, not
3739 * this number.
3740 */
3741 return (NULL);
3742 }
3743 return (dest);
3744 }
3745
3746 cur--;
3747 state = DTRACE_JSON_COMMA;
3748 break;
3749 case DTRACE_JSON_VALUE:
3750 if (isspace(cc))
3751 break;
3752
3753 if (cc == '{' || cc == '[') {
3754 if (nelems > 1 && found_key) {
3755 in_array = cc == '[' ? B_TRUE : B_FALSE;
3756 /*
3757 * If our element selector directs us
3758 * to descend into this nested object,
3759 * then move to the next selector
3760 * element in the list and restart the
3761 * state machine.
3762 */
3763 while (*elem != '\0')
3764 elem++;
3765 elem++; /* skip the inter-element NUL */
3766 nelems--;
3767 dd = dest;
3768 if (in_array) {
3769 state = DTRACE_JSON_VALUE;
3770 array_pos = 0;
3771 array_elem = dtrace_strtoll(
3772 elem, 10, size);
3773 found_key = array_elem == 0 ?
3774 B_TRUE : B_FALSE;
3775 } else {
3776 found_key = B_FALSE;
3777 state = DTRACE_JSON_OBJECT;
3778 }
3779 break;
3780 }
3781
3782 /*
3783 * Otherwise, we wish to either skip this
3784 * nested object or return it in full.
3785 */
3786 if (cc == '[')
3787 brackets = 1;
3788 else
3789 braces = 1;
3790 *dd++ = cc;
3791 state = DTRACE_JSON_COLLECT_OBJECT;
3792 break;
3793 }
3794
3795 if (cc == '"') {
3796 state = DTRACE_JSON_STRING;
3797 break;
3798 }
3799
3800 if (islower(cc)) {
3801 /*
3802 * Here we deal with true, false and null.
3803 */
3804 *dd++ = cc;
3805 state = DTRACE_JSON_IDENTIFIER;
3806 break;
3807 }
3808
3809 if (cc == '-' || isdigit(cc)) {
3810 *dd++ = cc;
3811 state = DTRACE_JSON_NUMBER;
3812 break;
3813 }
3814
3815 /*
3816 * ERROR: unexpected character at start of value.
3817 */
3818 return (NULL);
3819 case DTRACE_JSON_COLLECT_OBJECT:
3820 if (cc == '\0')
3821 /*
3822 * ERROR: unexpected end of input.
3823 */
3824 return (NULL);
3825
3826 *dd++ = cc;
3827 if (cc == '"') {
3828 collect_object = B_TRUE;
3829 state = DTRACE_JSON_STRING;
3830 break;
3831 }
3832
3833 if (cc == ']') {
3834 if (brackets-- == 0) {
3835 /*
3836 * ERROR: unbalanced brackets.
3837 */
3838 return (NULL);
3839 }
3840 } else if (cc == '}') {
3841 if (braces-- == 0) {
3842 /*
3843 * ERROR: unbalanced braces.
3844 */
3845 return (NULL);
3846 }
3847 } else if (cc == '{') {
3848 braces++;
3849 } else if (cc == '[') {
3850 brackets++;
3851 }
3852
3853 if (brackets == 0 && braces == 0) {
3854 if (found_key) {
3855 *dd = '\0';
3856 return (dest);
3857 }
3858 dd = dest; /* reset string buffer */
3859 state = DTRACE_JSON_COMMA;
3860 }
3861 break;
3862 }
3863 }
3864 return (NULL);
3865 }
3866
3867 /*
3868 * Emulate the execution of DTrace ID subroutines invoked by the call opcode.
3869 * Notice that we don't bother validating the proper number of arguments or
3870 * their types in the tuple stack. This isn't needed because all argument
3871 * interpretation is safe because of our load safety -- the worst that can
3872 * happen is that a bogus program can obtain bogus results.
3873 */
3874 static void
3875 dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
3876 dtrace_key_t *tupregs, int nargs,
3877 dtrace_mstate_t *mstate, dtrace_state_t *state)
3878 {
3879 volatile uint16_t *flags = &cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
4579
4580 if (!dtrace_canload(json, jsonlen + 1, mstate, vstate) ||
4581 !dtrace_canload(elem, elemlen + 1, mstate, vstate)) {
4582 regs[rd] = NULL;
4583 break;
4584 }
4585
4586 if (!DTRACE_INSCRATCH(mstate, jsonlen + 1 + elemlen + 1)) {
4587 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4588 regs[rd] = NULL;
4589 break;
4590 }
4591
4592 /*
4593 * Read the element selector and split it up into a packed list
4594 * of strings.
4595 */
4596 for (cur = elem; cur < elem + elemlen; cur++) {
4597 char cc = dtrace_load8(cur);
4598
4599 if (cur == elem && cc == '[') {
4600 /*
4601 * If the first element selector key is
4602 * actually an array index then ignore the
4603 * bracket.
4604 */
4605 continue;
4606 }
4607
4608 if (cc == ']')
4609 continue;
4610
4611 if (cc == '.' || cc == '[') {
4612 nelems++;
4613 cc = '\0';
4614 }
4615
4616 *ee++ = cc;
4617 }
4618 *ee++ = '\0';
4619
4620 if ((regs[rd] = (uintptr_t)dtrace_json(size, json, elemlist,
4621 nelems, dest)) != NULL)
4622 mstate->dtms_scratch_ptr += jsonlen + 1;
4623 break;
4624 }
4625
4626 case DIF_SUBR_TOUPPER:
|