MFV illumos
4477 DTrace should speak JSON MFC after: 2 weeks
This commit is contained in:
commit
c6d679e670
@ -22,6 +22,7 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
@ -98,6 +99,8 @@ STRFUNC(inet_ntoa((ipaddr_t *)alloca(sizeof (ipaddr_t))))
|
||||
STRFUNC(inet_ntoa6((in6_addr_t *)alloca(sizeof (in6_addr_t))))
|
||||
STRFUNC(inet_ntop(AF_INET, (void *)alloca(sizeof (ipaddr_t))))
|
||||
INTFUNC(getf(0))
|
||||
INTFUNC(strtoll("0x12EE5D5", 16))
|
||||
STRFUNC(json("{\"systemtap\": false}", "systemtap"))
|
||||
|
||||
BEGIN
|
||||
/subr == DIF_SUBR_MAX + 1/
|
||||
|
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* This file and its contents are supplied under the terms of the
|
||||
* Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
* You may only use this file in accordance with the terms of version
|
||||
* 1.0 of the CDDL.
|
||||
*
|
||||
* A full copy of the text of the CDDL should have accompanied this
|
||||
* source. A copy of the CDDL is also available via the Internet at
|
||||
* http://www.illumos.org/license/CDDL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2012, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* General functional tests of JSON parser for json().
|
||||
*/
|
||||
|
||||
#pragma D option quiet
|
||||
#pragma D option strsize=1k
|
||||
|
||||
#define TST(name) \
|
||||
printf("\ntst |%s|\n", name)
|
||||
#define IN2(vala, valb) \
|
||||
in = strjoin(vala, valb); \
|
||||
printf("in |%s|\n", in)
|
||||
#define IN(val) \
|
||||
in = val; \
|
||||
printf("in |%s|\n", in)
|
||||
#define SEL(ss) \
|
||||
out = json(in, ss); \
|
||||
printf("sel |%s|\nout |%s|\n", ss, \
|
||||
out != NULL ? out : "<NULL>")
|
||||
|
||||
BEGIN
|
||||
{
|
||||
TST("empty array");
|
||||
IN("[]");
|
||||
SEL("0");
|
||||
|
||||
TST("one-element array: integer");
|
||||
IN("[1]");
|
||||
SEL("0");
|
||||
SEL("1");
|
||||
SEL("100");
|
||||
SEL("-1");
|
||||
|
||||
TST("one-element array: hex integer (not in spec, not supported)");
|
||||
IN("[0x1000]");
|
||||
SEL("0");
|
||||
|
||||
TST("one-element array: float");
|
||||
IN("[1.5001]");
|
||||
SEL("0");
|
||||
|
||||
TST("one-element array: float + exponent");
|
||||
IN("[16.3e10]");
|
||||
SEL("0");
|
||||
|
||||
TST("one-element array: integer + whitespace");
|
||||
IN("[ \t 5\t]");
|
||||
SEL("0");
|
||||
|
||||
TST("one-element array: integer + exponent + whitespace");
|
||||
IN("[ \t \t 16E10 \t ]");
|
||||
SEL("0");
|
||||
|
||||
TST("one-element array: string");
|
||||
IN("[\"alpha\"]");
|
||||
SEL("0");
|
||||
|
||||
TST("alternative first-element indexing");
|
||||
IN("[1,5,10,15,20]");
|
||||
SEL("[0]");
|
||||
SEL("[3]");
|
||||
SEL("[4]");
|
||||
SEL("[5]");
|
||||
|
||||
TST("one-element array: object");
|
||||
IN("[ { \"first\": true, \"second\": false }]");
|
||||
SEL("0.first");
|
||||
SEL("0.second");
|
||||
SEL("0.third");
|
||||
|
||||
TST("many-element array: integers");
|
||||
IN("[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377]");
|
||||
SEL("10"); /* F(10) = 55 */
|
||||
SEL("14"); /* F(14) = 377 */
|
||||
SEL("19");
|
||||
|
||||
TST("many-element array: multiple types");
|
||||
IN2("[\"string\",32,true,{\"a\":9,\"b\":false},100.3e10,false,200.5,",
|
||||
"{\"key\":\"val\"},null]");
|
||||
SEL("0");
|
||||
SEL("0.notobject");
|
||||
SEL("1");
|
||||
SEL("2");
|
||||
SEL("3");
|
||||
SEL("3.a");
|
||||
SEL("3.b");
|
||||
SEL("3.c");
|
||||
SEL("4");
|
||||
SEL("5");
|
||||
SEL("6");
|
||||
SEL("7");
|
||||
SEL("7.key");
|
||||
SEL("7.key.notobject");
|
||||
SEL("7.nonexist");
|
||||
SEL("8");
|
||||
SEL("9");
|
||||
|
||||
TST("many-element array: multiple types + whitespace");
|
||||
IN2("\n[\t\"string\" ,\t32 , true\t,\t {\"a\": 9,\t\"b\": false},\t\t",
|
||||
"100.3e10, false, 200.5,{\"key\" \t:\n \"val\"},\t\t null ]\t\t");
|
||||
SEL("0");
|
||||
SEL("0.notobject");
|
||||
SEL("1");
|
||||
SEL("2");
|
||||
SEL("3");
|
||||
SEL("3.a");
|
||||
SEL("3.b");
|
||||
SEL("3.c");
|
||||
SEL("4");
|
||||
SEL("5");
|
||||
SEL("6");
|
||||
SEL("7");
|
||||
SEL("7.key");
|
||||
SEL("7.key.notobject");
|
||||
SEL("7.nonexist");
|
||||
SEL("8");
|
||||
SEL("9");
|
||||
|
||||
TST("two-element array: various string escape codes");
|
||||
IN2("[\"abcd \\\" \\\\ \\/ \\b \\f \\n \\r \\t \\u0000 \\uf00F \", ",
|
||||
"\"final\"]");
|
||||
SEL("0");
|
||||
SEL("1");
|
||||
|
||||
TST("three-element array: broken escape code");
|
||||
IN("[\"fine here\", \"dodgey \\u00AZ\", \"wont get here\"]");
|
||||
SEL("0");
|
||||
SEL("1");
|
||||
SEL("2");
|
||||
|
||||
TST("nested objects");
|
||||
IN2("{ \"top\": { \"mid\" : { \"legs\": \"feet\" }, \"number\": 9, ",
|
||||
"\"array\":[0,1,{\"a\":true,\"bb\":[1,2,false,{\"x\":\"yz\"}]}]}}");
|
||||
SEL("top");
|
||||
SEL("fargo");
|
||||
SEL("top.mid");
|
||||
SEL("top.centre");
|
||||
SEL("top.mid.legs");
|
||||
SEL("top.mid.number");
|
||||
SEL("top.mid.array");
|
||||
SEL("top.number");
|
||||
SEL("top.array");
|
||||
SEL("top.array[0]");
|
||||
SEL("top.array[1]");
|
||||
SEL("top.array[2]");
|
||||
SEL("top.array[2].a");
|
||||
SEL("top.array[2].b");
|
||||
SEL("top.array[2].bb");
|
||||
SEL("top.array[2].bb[0]");
|
||||
SEL("top.array[2].bb[1]");
|
||||
SEL("top.array[2].bb[2]");
|
||||
SEL("top.array[2].bb[3]");
|
||||
SEL("top.array[2].bb[3].x");
|
||||
SEL("top.array[2].bb[3].x.nofurther");
|
||||
SEL("top.array[2].bb[4]");
|
||||
SEL("top.array[3]");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ERROR
|
||||
{
|
||||
exit(1);
|
||||
}
|
@ -0,0 +1,218 @@
|
||||
|
||||
tst |empty array|
|
||||
in |[]|
|
||||
sel |0|
|
||||
out |<NULL>|
|
||||
|
||||
tst |one-element array: integer|
|
||||
in |[1]|
|
||||
sel |0|
|
||||
out |1|
|
||||
sel |1|
|
||||
out |<NULL>|
|
||||
sel |100|
|
||||
out |<NULL>|
|
||||
sel |-1|
|
||||
out |<NULL>|
|
||||
|
||||
tst |one-element array: hex integer (not in spec, not supported)|
|
||||
in |[0x1000]|
|
||||
sel |0|
|
||||
out |<NULL>|
|
||||
|
||||
tst |one-element array: float|
|
||||
in |[1.5001]|
|
||||
sel |0|
|
||||
out |1.5001|
|
||||
|
||||
tst |one-element array: float + exponent|
|
||||
in |[16.3e10]|
|
||||
sel |0|
|
||||
out |16.3e10|
|
||||
|
||||
tst |one-element array: integer + whitespace|
|
||||
in |[ 5 ]|
|
||||
sel |0|
|
||||
out |5|
|
||||
|
||||
tst |one-element array: integer + exponent + whitespace|
|
||||
in |[ 16E10 ]|
|
||||
sel |0|
|
||||
out |16E10|
|
||||
|
||||
tst |one-element array: string|
|
||||
in |["alpha"]|
|
||||
sel |0|
|
||||
out |alpha|
|
||||
|
||||
tst |alternative first-element indexing|
|
||||
in |[1,5,10,15,20]|
|
||||
sel |[0]|
|
||||
out |1|
|
||||
sel |[3]|
|
||||
out |15|
|
||||
sel |[4]|
|
||||
out |20|
|
||||
sel |[5]|
|
||||
out |<NULL>|
|
||||
|
||||
tst |one-element array: object|
|
||||
in |[ { "first": true, "second": false }]|
|
||||
sel |0.first|
|
||||
out |true|
|
||||
sel |0.second|
|
||||
out |false|
|
||||
sel |0.third|
|
||||
out |<NULL>|
|
||||
|
||||
tst |many-element array: integers|
|
||||
in |[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377]|
|
||||
sel |10|
|
||||
out |55|
|
||||
sel |14|
|
||||
out |377|
|
||||
sel |19|
|
||||
out |<NULL>|
|
||||
|
||||
tst |many-element array: multiple types|
|
||||
in |["string",32,true,{"a":9,"b":false},100.3e10,false,200.5,{"key":"val"},null]|
|
||||
sel |0|
|
||||
out |string|
|
||||
sel |0.notobject|
|
||||
out |<NULL>|
|
||||
sel |1|
|
||||
out |32|
|
||||
sel |2|
|
||||
out |true|
|
||||
sel |3|
|
||||
out |{"a":9,"b":false}|
|
||||
sel |3.a|
|
||||
out |9|
|
||||
sel |3.b|
|
||||
out |false|
|
||||
sel |3.c|
|
||||
out |<NULL>|
|
||||
sel |4|
|
||||
out |100.3e10|
|
||||
sel |5|
|
||||
out |false|
|
||||
sel |6|
|
||||
out |200.5|
|
||||
sel |7|
|
||||
out |{"key":"val"}|
|
||||
sel |7.key|
|
||||
out |val|
|
||||
sel |7.key.notobject|
|
||||
out |<NULL>|
|
||||
sel |7.nonexist|
|
||||
out |<NULL>|
|
||||
sel |8|
|
||||
out |null|
|
||||
sel |9|
|
||||
out |<NULL>|
|
||||
|
||||
tst |many-element array: multiple types + whitespace|
|
||||
in |
|
||||
[ "string" , 32 , true , {"a": 9, "b": false}, 100.3e10, false, 200.5,{"key" :
|
||||
"val"}, null ] |
|
||||
sel |0|
|
||||
out |string|
|
||||
sel |0.notobject|
|
||||
out |<NULL>|
|
||||
sel |1|
|
||||
out |32|
|
||||
sel |2|
|
||||
out |true|
|
||||
sel |3|
|
||||
out |{"a": 9, "b": false}|
|
||||
sel |3.a|
|
||||
out |9|
|
||||
sel |3.b|
|
||||
out |false|
|
||||
sel |3.c|
|
||||
out |<NULL>|
|
||||
sel |4|
|
||||
out |100.3e10|
|
||||
sel |5|
|
||||
out |false|
|
||||
sel |6|
|
||||
out |200.5|
|
||||
sel |7|
|
||||
out |{"key" :
|
||||
"val"}|
|
||||
sel |7.key|
|
||||
out |val|
|
||||
sel |7.key.notobject|
|
||||
out |<NULL>|
|
||||
sel |7.nonexist|
|
||||
out |<NULL>|
|
||||
sel |8|
|
||||
out |null|
|
||||
sel |9|
|
||||
out |<NULL>|
|
||||
|
||||
tst |two-element array: various string escape codes|
|
||||
in |["abcd \" \\ \/ \b \f \n \r \t \u0000 \uf00F ", "final"]|
|
||||
sel |0|
|
||||
out |abcd \" \\ \/ \b \f \n \r \t \u0000 \uf00F |
|
||||
sel |1|
|
||||
out |final|
|
||||
|
||||
tst |three-element array: broken escape code|
|
||||
in |["fine here", "dodgey \u00AZ", "wont get here"]|
|
||||
sel |0|
|
||||
out |fine here|
|
||||
sel |1|
|
||||
out |<NULL>|
|
||||
sel |2|
|
||||
out |<NULL>|
|
||||
|
||||
tst |nested objects|
|
||||
in |{ "top": { "mid" : { "legs": "feet" }, "number": 9, "array":[0,1,{"a":true,"bb":[1,2,false,{"x":"yz"}]}]}}|
|
||||
sel |top|
|
||||
out |{ "mid" : { "legs": "feet" }, "number": 9, "array":[0,1,{"a":true,"bb":[1,2,false,{"x":"yz"}]}]}|
|
||||
sel |fargo|
|
||||
out |<NULL>|
|
||||
sel |top.mid|
|
||||
out |{ "legs": "feet" }|
|
||||
sel |top.centre|
|
||||
out |<NULL>|
|
||||
sel |top.mid.legs|
|
||||
out |feet|
|
||||
sel |top.mid.number|
|
||||
out |<NULL>|
|
||||
sel |top.mid.array|
|
||||
out |<NULL>|
|
||||
sel |top.number|
|
||||
out |9|
|
||||
sel |top.array|
|
||||
out |[0,1,{"a":true,"bb":[1,2,false,{"x":"yz"}]}]|
|
||||
sel |top.array[0]|
|
||||
out |0|
|
||||
sel |top.array[1]|
|
||||
out |1|
|
||||
sel |top.array[2]|
|
||||
out |{"a":true,"bb":[1,2,false,{"x":"yz"}]}|
|
||||
sel |top.array[2].a|
|
||||
out |true|
|
||||
sel |top.array[2].b|
|
||||
out |<NULL>|
|
||||
sel |top.array[2].bb|
|
||||
out |[1,2,false,{"x":"yz"}]|
|
||||
sel |top.array[2].bb[0]|
|
||||
out |1|
|
||||
sel |top.array[2].bb[1]|
|
||||
out |2|
|
||||
sel |top.array[2].bb[2]|
|
||||
out |false|
|
||||
sel |top.array[2].bb[3]|
|
||||
out |{"x":"yz"}|
|
||||
sel |top.array[2].bb[3].x|
|
||||
out |yz|
|
||||
sel |top.array[2].bb[3].x.nofurther|
|
||||
out |<NULL>|
|
||||
sel |top.array[2].bb[4]|
|
||||
out |<NULL>|
|
||||
sel |top.array[3]|
|
||||
out |<NULL>|
|
||||
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file and its contents are supplied under the terms of the
|
||||
* Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
* You may only use this file in accordance with the terms of version
|
||||
* 1.0 of the CDDL.
|
||||
*
|
||||
* A full copy of the text of the CDDL should have accompanied this
|
||||
* source. A copy of the CDDL is also available via the Internet at
|
||||
* http://www.illumos.org/license/CDDL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2012, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ASSERTION:
|
||||
* json() run time must be bounded above by strsize. This test makes strsize
|
||||
* small and deliberately overflows it to prove we bail and return NULL in
|
||||
* the event that we run off the end of the string.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma D option quiet
|
||||
#pragma D option strsize=18
|
||||
|
||||
BEGIN
|
||||
{
|
||||
in = "{\"a\": 1024}"; /* length == 19 */
|
||||
out = json(in, "a");
|
||||
printf("|%s|\n%s\n\n", in, out != NULL ? out : "<NULL>");
|
||||
|
||||
in = "{\"a\": 1024}"; /* length == 11 */
|
||||
out = json(in, "a");
|
||||
printf("|%s|\n%s\n\n", in, out != NULL ? out : "<NULL>");
|
||||
|
||||
in = "{\"a\":false,\"b\":true}"; /* length == 20 */
|
||||
out = json(in, "b");
|
||||
printf("|%s|\n%s\n\n", in, out != NULL ? out : "<NULL>");
|
||||
|
||||
in = "{\"a\":false,\"b\":20}"; /* length == 18 */
|
||||
out = json(in, "b");
|
||||
printf("|%s|\n%s\n\n", in, out != NULL ? out : "<NULL>");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ERROR
|
||||
{
|
||||
exit(1);
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
|{"a": 1024|
|
||||
<NULL>
|
||||
|
||||
|{"a": 1024}|
|
||||
1024
|
||||
|
||||
|{"a":false,"b":tru|
|
||||
<NULL>
|
||||
|
||||
|{"a":false,"b":20}|
|
||||
20
|
||||
|
||||
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This file and its contents are supplied under the terms of the
|
||||
* Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
* You may only use this file in accordance with the terms of version
|
||||
* 1.0 of the CDDL.
|
||||
*
|
||||
* A full copy of the text of the CDDL should have accompanied this
|
||||
* source. A copy of the CDDL is also available via the Internet at
|
||||
* http://www.illumos.org/license/CDDL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2012 (c), Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/sdt.h>
|
||||
#include "usdt.h"
|
||||
|
||||
#define FMT "{" \
|
||||
" \"sizes\": [ \"first\", 2, %f ]," \
|
||||
" \"index\": %d," \
|
||||
" \"facts\": {" \
|
||||
" \"odd\": \"%s\"," \
|
||||
" \"even\": \"%s\"" \
|
||||
" }," \
|
||||
" \"action\": \"%s\"" \
|
||||
"}\n"
|
||||
|
||||
int
|
||||
waiting(volatile int *a)
|
||||
{
|
||||
return (*a);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
volatile int a = 0;
|
||||
int idx;
|
||||
double size = 250.5;
|
||||
|
||||
while (waiting(&a) == 0)
|
||||
continue;
|
||||
|
||||
for (idx = 0; idx < 10; idx++) {
|
||||
char *odd, *even, *json, *action;
|
||||
|
||||
size *= 1.78;
|
||||
odd = idx % 2 == 1 ? "true" : "false";
|
||||
even = idx % 2 == 0 ? "true" : "false";
|
||||
action = idx == 7 ? "ignore" : "print";
|
||||
|
||||
asprintf(&json, FMT, size, idx, odd, even, action);
|
||||
BUNYAN_FAKE_LOG_DEBUG(json);
|
||||
free(json);
|
||||
}
|
||||
|
||||
BUNYAN_FAKE_LOG_DEBUG("{\"finished\": true}");
|
||||
|
||||
return (0);
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* This file and its contents are supplied under the terms of the
|
||||
* Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
* You may only use this file in accordance with the terms of version
|
||||
* 1.0 of the CDDL.
|
||||
*
|
||||
* A full copy of the text of the CDDL should have accompanied this
|
||||
* source. A copy of the CDDL is also available via the Internet at
|
||||
* http://www.illumos.org/license/CDDL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma D option strsize=4k
|
||||
#pragma D option quiet
|
||||
#pragma D option destructive
|
||||
|
||||
/*
|
||||
* This test reads a JSON string from a USDT probe, roughly simulating the
|
||||
* primary motivating use case for the json() subroutine: filtering
|
||||
* JSON-formatted log messages from a logging subsystem like node-bunyan.
|
||||
*/
|
||||
|
||||
pid$1:a.out:waiting:entry
|
||||
{
|
||||
this->value = (int *)alloca(sizeof (int));
|
||||
*this->value = 1;
|
||||
copyout(this->value, arg0, sizeof (int));
|
||||
}
|
||||
|
||||
bunyan*$1:::log-*
|
||||
{
|
||||
this->j = copyinstr(arg0);
|
||||
}
|
||||
|
||||
bunyan*$1:::log-*
|
||||
/json(this->j, "finished") == NULL && json(this->j, "action") != "ignore"/
|
||||
{
|
||||
this->index = strtoll(json(this->j, "index"));
|
||||
this->size = json(this->j, "sizes[2]");
|
||||
this->odd = json(this->j, "facts.odd");
|
||||
this->even = json(this->j, "facts.even");
|
||||
printf("[%d] sz %s odd %s even %s\n", this->index, this->size,
|
||||
this->odd, this->even);
|
||||
}
|
||||
|
||||
bunyan*$1:::log-*
|
||||
/json(this->j, "finished") != NULL/
|
||||
{
|
||||
printf("FINISHED!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
tick-10s
|
||||
{
|
||||
printf("ERROR: Timed out before finish message!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ERROR
|
||||
{
|
||||
exit(1);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
[0] sz 445.890000 odd false even true
|
||||
[1] sz 793.684200 odd true even false
|
||||
[2] sz 1412.757876 odd false even true
|
||||
[3] sz 2514.709019 odd true even false
|
||||
[4] sz 4476.182054 odd false even true
|
||||
[5] sz 7967.604057 odd true even false
|
||||
[6] sz 14182.335221 odd false even true
|
||||
[8] sz 44935.310914 odd false even true
|
||||
[9] sz 79984.853427 odd true even false
|
||||
FINISHED!
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file and its contents are supplied under the terms of the
|
||||
* Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
* You may only use this file in accordance with the terms of version
|
||||
* 1.0 of the CDDL.
|
||||
*
|
||||
* A full copy of the text of the CDDL should have accompanied this
|
||||
* source. A copy of the CDDL is also available via the Internet at
|
||||
* http://www.illumos.org/license/CDDL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2012, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Sets up a fake node-bunyan-like USDT provider for use from C.
|
||||
*/
|
||||
|
||||
provider bunyan_fake {
|
||||
probe log__trace(char *msg);
|
||||
probe log__debug(char *msg);
|
||||
probe log__info(char *msg);
|
||||
probe log__warn(char *msg);
|
||||
probe log__error(char *msg);
|
||||
probe log__fatal(char *msg);
|
||||
};
|
@ -22,8 +22,8 @@
|
||||
#
|
||||
# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
# Use is subject to license terms.
|
||||
# Copyright (c) 2012, Joyent, Inc. All rights reserved.
|
||||
#
|
||||
#ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
ppriv -s A=basic,dtrace_proc,dtrace_user $$
|
||||
|
||||
@ -31,7 +31,7 @@ ppriv -s A=basic,dtrace_proc,dtrace_user $$
|
||||
|
||||
BEGIN {
|
||||
errorcount = 0;
|
||||
expected_errorcount = 23;
|
||||
expected_errorcount = 27;
|
||||
}
|
||||
|
||||
BEGIN { trace(mutex_owned(&`pidlock)); }
|
||||
@ -55,6 +55,8 @@ BEGIN { trace(strtok(`initname, "/")); }
|
||||
BEGIN { trace(strtok(NULL, "/")); }
|
||||
BEGIN { trace(strtok("foo/bar", `initname)); }
|
||||
BEGIN { trace(strtok(NULL, `initname)); }
|
||||
BEGIN { trace(strtoll(`initname)); }
|
||||
BEGIN { trace(strtoll(`initname, 10)); }
|
||||
BEGIN { trace(substr(`initname, 2, 3)); }
|
||||
|
||||
BEGIN { trace(ddi_pathname(`top_devinfo, 1)); }
|
||||
@ -63,6 +65,9 @@ BEGIN { trace(strjoin("foo", `initname)); }
|
||||
BEGIN { trace(dirname(`initname)); }
|
||||
BEGIN { trace(cleanpath(`initname)); }
|
||||
|
||||
BEGIN { j = "{\"/sbin/init\":\"uh oh\"}"; trace(json(j, `initname)); }
|
||||
BEGIN { trace(json(`initname, "x")); }
|
||||
|
||||
ERROR {
|
||||
errorcount++;
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file and its contents are supplied under the terms of the
|
||||
* Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
* You may only use this file in accordance with the terms of version
|
||||
* 1.0 of the CDDL.
|
||||
*
|
||||
* A full copy of the text of the CDDL should have accompanied this
|
||||
* source. A copy of the CDDL is also available via the Internet at
|
||||
* http://www.illumos.org/license/CDDL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ASSERTION:
|
||||
* The largest base we will accept is Base 36 -- i.e. using all of 0-9 and
|
||||
* A-Z as numerals.
|
||||
*
|
||||
* SECTION: Actions and Subroutines/strtoll()
|
||||
*/
|
||||
|
||||
#pragma D option quiet
|
||||
|
||||
BEGIN
|
||||
{
|
||||
printf("%d\n", strtoll("0", 37));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ERROR
|
||||
{
|
||||
exit(1);
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file and its contents are supplied under the terms of the
|
||||
* Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
* You may only use this file in accordance with the terms of version
|
||||
* 1.0 of the CDDL.
|
||||
*
|
||||
* A full copy of the text of the CDDL should have accompanied this
|
||||
* source. A copy of the CDDL is also available via the Internet at
|
||||
* http://www.illumos.org/license/CDDL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ASSERTION:
|
||||
* The smallest base we will accept is Base 2.
|
||||
*
|
||||
* SECTION: Actions and Subroutines/strtoll()
|
||||
*/
|
||||
|
||||
#pragma D option quiet
|
||||
|
||||
BEGIN
|
||||
{
|
||||
printf("%d\n", strtoll("0", 1));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ERROR
|
||||
{
|
||||
exit(1);
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* This file and its contents are supplied under the terms of the
|
||||
* Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
* You may only use this file in accordance with the terms of version
|
||||
* 1.0 of the CDDL.
|
||||
*
|
||||
* A full copy of the text of the CDDL should have accompanied this
|
||||
* source. A copy of the CDDL is also available via the Internet at
|
||||
* http://www.illumos.org/license/CDDL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ASSERTION:
|
||||
* Test the strtoll() subroutine.
|
||||
*
|
||||
* SECTION: Actions and Subroutines/strtoll()
|
||||
*/
|
||||
|
||||
#pragma D option quiet
|
||||
|
||||
BEGIN
|
||||
{
|
||||
|
||||
/* minimum base (2) and maximum base (36): */
|
||||
printf("%d\n", strtoll("0", 2));
|
||||
printf("%d\n", strtoll("1", 36));
|
||||
|
||||
/* simple tests: */
|
||||
printf("%d\n", strtoll("0x20", 16));
|
||||
printf("%d\n", strtoll("-32", 10));
|
||||
printf("%d\n", strtoll("010", 8));
|
||||
printf("%d\n", strtoll("101010", 2));
|
||||
|
||||
/* INT64_MIN and INT64_MAX: */
|
||||
printf("%d\n", strtoll("9223372036854775807"));
|
||||
printf("%d\n", strtoll("-9223372036854775808"));
|
||||
printf("%d\n", strtoll("0777777777777777777777", 8));
|
||||
printf("%d\n", strtoll("-01000000000000000000000", 8));
|
||||
|
||||
/* wrapping: */
|
||||
printf("%d\n", strtoll("1000000000000000000000", 8));
|
||||
printf("%d\n", strtoll("-1000000000000000000001", 8));
|
||||
|
||||
/* hex without prefix: */
|
||||
printf("%d\n", strtoll("baddcafe", 16));
|
||||
|
||||
/* stopping at first out-of-base character: */
|
||||
printf("%d\n", strtoll("12j", 10));
|
||||
printf("%d\n", strtoll("102", 2));
|
||||
|
||||
/* base 36: */
|
||||
printf("%d\n", strtoll("-0DTrace4EverZ", 36));
|
||||
|
||||
/* base 10 is assumed: */
|
||||
printf("%d\n", strtoll("1985"));
|
||||
printf("%d\n", strtoll("-2012"));
|
||||
|
||||
/* empty string: */
|
||||
printf("%d\n", strtoll(""));
|
||||
|
||||
exit(0);
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
0
|
||||
1
|
||||
32
|
||||
-32
|
||||
8
|
||||
42
|
||||
9223372036854775807
|
||||
-9223372036854775808
|
||||
9223372036854775807
|
||||
-9223372036854775808
|
||||
-9223372036854775808
|
||||
9223372036854775807
|
||||
3135097598
|
||||
12
|
||||
2
|
||||
-1819882045752187535
|
||||
1985
|
||||
-2012
|
||||
0
|
||||
|
79
cddl/contrib/opensolaris/common/util/strtolctype.h
Normal file
79
cddl/contrib/opensolaris/common/util/strtolctype.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1988 AT&T */
|
||||
/* All Rights Reserved */
|
||||
|
||||
#ifndef _COMMON_UTIL_CTYPE_H
|
||||
#define _COMMON_UTIL_CTYPE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This header file contains a collection of macros that the strtou?ll?
|
||||
* functions in common/util use to test characters. What we need is a kernel
|
||||
* version of ctype.h.
|
||||
*
|
||||
* NOTE: These macros are used within several DTrace probe context functions.
|
||||
* They must not be altered to make function calls or perform actions not
|
||||
* safe in probe context.
|
||||
*/
|
||||
|
||||
#if defined(sun) && (defined(_KERNEL) || defined(_BOOT))
|
||||
|
||||
#define isalnum(ch) (isalpha(ch) || isdigit(ch))
|
||||
#define isalpha(ch) (isupper(ch) || islower(ch))
|
||||
#define isdigit(ch) ((ch) >= '0' && (ch) <= '9')
|
||||
#define islower(ch) ((ch) >= 'a' && (ch) <= 'z')
|
||||
#define isspace(ch) (((ch) == ' ') || ((ch) == '\r') || ((ch) == '\n') || \
|
||||
((ch) == '\t') || ((ch) == '\f'))
|
||||
#define isupper(ch) ((ch) >= 'A' && (ch) <= 'Z')
|
||||
#define isxdigit(ch) (isdigit(ch) || ((ch) >= 'a' && (ch) <= 'f') || \
|
||||
((ch) >= 'A' && (ch) <= 'F'))
|
||||
|
||||
#endif /* _KERNEL || _BOOT */
|
||||
|
||||
#define DIGIT(x) \
|
||||
(isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
|
||||
|
||||
#define MBASE ('z' - 'a' + 1 + 10)
|
||||
|
||||
/*
|
||||
* The following macro is a version of isalnum() that limits alphabetic
|
||||
* characters to the ranges a-z and A-Z; locale dependent characters will not
|
||||
* return 1. The members of a-z and A-Z are assumed to be in ascending order
|
||||
* and contiguous.
|
||||
*/
|
||||
#define lisalnum(x) \
|
||||
(isdigit(x) || ((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z'))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _COMMON_UTIL_CTYPE_H */
|
@ -123,8 +123,9 @@
|
||||
#define DT_VERS_1_9 DT_VERSION_NUMBER(1, 9, 0)
|
||||
#define DT_VERS_1_9_1 DT_VERSION_NUMBER(1, 9, 1)
|
||||
#define DT_VERS_1_10 DT_VERSION_NUMBER(1, 10, 0)
|
||||
#define DT_VERS_LATEST DT_VERS_1_10
|
||||
#define DT_VERS_STRING "Sun D 1.10"
|
||||
#define DT_VERS_1_11 DT_VERSION_NUMBER(1, 11, 0)
|
||||
#define DT_VERS_LATEST DT_VERS_1_11
|
||||
#define DT_VERS_STRING "Sun D 1.11"
|
||||
|
||||
const dt_version_t _dtrace_versions[] = {
|
||||
DT_VERS_1_0, /* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */
|
||||
@ -147,6 +148,7 @@ const dt_version_t _dtrace_versions[] = {
|
||||
DT_VERS_1_9, /* D API 1.9 */
|
||||
DT_VERS_1_9_1, /* D API 1.9.1 */
|
||||
DT_VERS_1_10, /* D API 1.10 */
|
||||
DT_VERS_1_11, /* D API 1.11 */
|
||||
0
|
||||
};
|
||||
|
||||
@ -301,6 +303,8 @@ static const dt_ident_t _dtrace_globals[] = {
|
||||
DT_VERS_1_5, &dt_idops_func, "string(int, void *)" },
|
||||
{ "ipl", DT_IDENT_SCALAR, 0, DIF_VAR_IPL, DT_ATTR_STABCMN, DT_VERS_1_0,
|
||||
&dt_idops_type, "uint_t" },
|
||||
{ "json", DT_IDENT_FUNC, 0, DIF_SUBR_JSON, DT_ATTR_STABCMN, DT_VERS_1_11,
|
||||
&dt_idops_func, "string(const char *, const char *)" },
|
||||
{ "jstack", DT_IDENT_ACTFUNC, 0, DT_ACT_JSTACK, DT_ATTR_STABCMN, DT_VERS_1_0,
|
||||
&dt_idops_func, "stack(...)" },
|
||||
{ "lltostr", DT_IDENT_FUNC, 0, DIF_SUBR_LLTOSTR, DT_ATTR_STABCMN, DT_VERS_1_0,
|
||||
@ -452,6 +456,8 @@ static const dt_ident_t _dtrace_globals[] = {
|
||||
&dt_idops_func, "string(const char *, const char *)" },
|
||||
{ "strtok", DT_IDENT_FUNC, 0, DIF_SUBR_STRTOK, DT_ATTR_STABCMN, DT_VERS_1_1,
|
||||
&dt_idops_func, "string(const char *, const char *)" },
|
||||
{ "strtoll", DT_IDENT_FUNC, 0, DIF_SUBR_STRTOLL, DT_ATTR_STABCMN, DT_VERS_1_11,
|
||||
&dt_idops_func, "int64_t(const char *, [int])" },
|
||||
{ "substr", DT_IDENT_FUNC, 0, DIF_SUBR_SUBSTR, DT_ATTR_STABCMN, DT_VERS_1_1,
|
||||
&dt_idops_func, "string(const char *, int, [int])" },
|
||||
{ "sum", DT_IDENT_AGGFUNC, 0, DTRACEAGG_SUM, DT_ATTR_STABCMN, DT_VERS_1_0,
|
||||
|
@ -111,6 +111,7 @@
|
||||
#include <sys/zone.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include "strtolctype.h"
|
||||
|
||||
/* FreeBSD includes: */
|
||||
#if !defined(sun)
|
||||
@ -966,6 +967,58 @@ dtrace_vcanload(void *src, dtrace_diftype_t *type, dtrace_mstate_t *mstate,
|
||||
return (dtrace_canload((uintptr_t)src, sz, mstate, vstate));
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a string to a signed integer using safe loads.
|
||||
*
|
||||
* NOTE: This function uses various macros from strtolctype.h to manipulate
|
||||
* digit values, etc -- these have all been checked to ensure they make
|
||||
* no additional function calls.
|
||||
*/
|
||||
static int64_t
|
||||
dtrace_strtoll(char *input, int base, size_t limit)
|
||||
{
|
||||
uintptr_t pos = (uintptr_t)input;
|
||||
int64_t val = 0;
|
||||
int x;
|
||||
boolean_t neg = B_FALSE;
|
||||
char c, cc, ccc;
|
||||
uintptr_t end = pos + limit;
|
||||
|
||||
/*
|
||||
* Consume any whitespace preceding digits.
|
||||
*/
|
||||
while ((c = dtrace_load8(pos)) == ' ' || c == '\t')
|
||||
pos++;
|
||||
|
||||
/*
|
||||
* Handle an explicit sign if one is present.
|
||||
*/
|
||||
if (c == '-' || c == '+') {
|
||||
if (c == '-')
|
||||
neg = B_TRUE;
|
||||
c = dtrace_load8(++pos);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for an explicit hexadecimal prefix ("0x" or "0X") and skip it
|
||||
* if present.
|
||||
*/
|
||||
if (base == 16 && c == '0' && ((cc = dtrace_load8(pos + 1)) == 'x' ||
|
||||
cc == 'X') && isxdigit(ccc = dtrace_load8(pos + 2))) {
|
||||
pos += 2;
|
||||
c = ccc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read in contiguous digits until the first non-digit character.
|
||||
*/
|
||||
for (; pos < end && c != '\0' && lisalnum(c) && (x = DIGIT(c)) < base;
|
||||
c = dtrace_load8(++pos))
|
||||
val = val * base + x;
|
||||
|
||||
return (neg ? -val : val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare two strings using safe loads.
|
||||
*/
|
||||
@ -3469,6 +3522,463 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef enum dtrace_json_state {
|
||||
DTRACE_JSON_REST = 1,
|
||||
DTRACE_JSON_OBJECT,
|
||||
DTRACE_JSON_STRING,
|
||||
DTRACE_JSON_STRING_ESCAPE,
|
||||
DTRACE_JSON_STRING_ESCAPE_UNICODE,
|
||||
DTRACE_JSON_COLON,
|
||||
DTRACE_JSON_COMMA,
|
||||
DTRACE_JSON_VALUE,
|
||||
DTRACE_JSON_IDENTIFIER,
|
||||
DTRACE_JSON_NUMBER,
|
||||
DTRACE_JSON_NUMBER_FRAC,
|
||||
DTRACE_JSON_NUMBER_EXP,
|
||||
DTRACE_JSON_COLLECT_OBJECT
|
||||
} dtrace_json_state_t;
|
||||
|
||||
/*
|
||||
* This function possesses just enough knowledge about JSON to extract a single
|
||||
* value from a JSON string and store it in the scratch buffer. It is able
|
||||
* to extract nested object values, and members of arrays by index.
|
||||
*
|
||||
* elemlist is a list of JSON keys, stored as packed NUL-terminated strings, to
|
||||
* be looked up as we descend into the object tree. e.g.
|
||||
*
|
||||
* foo[0].bar.baz[32] --> "foo" NUL "0" NUL "bar" NUL "baz" NUL "32" NUL
|
||||
* with nelems = 5.
|
||||
*
|
||||
* The run time of this function must be bounded above by strsize to limit the
|
||||
* amount of work done in probe context. As such, it is implemented as a
|
||||
* simple state machine, reading one character at a time using safe loads
|
||||
* until we find the requested element, hit a parsing error or run off the
|
||||
* end of the object or string.
|
||||
*
|
||||
* As there is no way for a subroutine to return an error without interrupting
|
||||
* clause execution, we simply return NULL in the event of a missing key or any
|
||||
* other error condition. Each NULL return in this function is commented with
|
||||
* the error condition it represents -- parsing or otherwise.
|
||||
*
|
||||
* The set of states for the state machine closely matches the JSON
|
||||
* specification (http://json.org/). Briefly:
|
||||
*
|
||||
* DTRACE_JSON_REST:
|
||||
* Skip whitespace until we find either a top-level Object, moving
|
||||
* to DTRACE_JSON_OBJECT; or an Array, moving to DTRACE_JSON_VALUE.
|
||||
*
|
||||
* DTRACE_JSON_OBJECT:
|
||||
* Locate the next key String in an Object. Sets a flag to denote
|
||||
* the next String as a key string and moves to DTRACE_JSON_STRING.
|
||||
*
|
||||
* DTRACE_JSON_COLON:
|
||||
* Skip whitespace until we find the colon that separates key Strings
|
||||
* from their values. Once found, move to DTRACE_JSON_VALUE.
|
||||
*
|
||||
* DTRACE_JSON_VALUE:
|
||||
* Detects the type of the next value (String, Number, Identifier, Object
|
||||
* or Array) and routes to the states that process that type. Here we also
|
||||
* deal with the element selector list if we are requested to traverse down
|
||||
* into the object tree.
|
||||
*
|
||||
* DTRACE_JSON_COMMA:
|
||||
* Skip whitespace until we find the comma that separates key-value pairs
|
||||
* in Objects (returning to DTRACE_JSON_OBJECT) or values in Arrays
|
||||
* (similarly DTRACE_JSON_VALUE). All following literal value processing
|
||||
* states return to this state at the end of their value, unless otherwise
|
||||
* noted.
|
||||
*
|
||||
* DTRACE_JSON_NUMBER, DTRACE_JSON_NUMBER_FRAC, DTRACE_JSON_NUMBER_EXP:
|
||||
* Processes a Number literal from the JSON, including any exponent
|
||||
* component that may be present. Numbers are returned as strings, which
|
||||
* may be passed to strtoll() if an integer is required.
|
||||
*
|
||||
* DTRACE_JSON_IDENTIFIER:
|
||||
* Processes a "true", "false" or "null" literal in the JSON.
|
||||
*
|
||||
* DTRACE_JSON_STRING, DTRACE_JSON_STRING_ESCAPE,
|
||||
* DTRACE_JSON_STRING_ESCAPE_UNICODE:
|
||||
* Processes a String literal from the JSON, whether the String denotes
|
||||
* a key, a value or part of a larger Object. Handles all escape sequences
|
||||
* present in the specification, including four-digit unicode characters,
|
||||
* but merely includes the escape sequence without converting it to the
|
||||
* actual escaped character. If the String is flagged as a key, we
|
||||
* move to DTRACE_JSON_COLON rather than DTRACE_JSON_COMMA.
|
||||
*
|
||||
* DTRACE_JSON_COLLECT_OBJECT:
|
||||
* This state collects an entire Object (or Array), correctly handling
|
||||
* embedded strings. If the full element selector list matches this nested
|
||||
* object, we return the Object in full as a string. If not, we use this
|
||||
* state to skip to the next value at this level and continue processing.
|
||||
*
|
||||
* NOTE: This function uses various macros from strtolctype.h to manipulate
|
||||
* digit values, etc -- these have all been checked to ensure they make
|
||||
* no additional function calls.
|
||||
*/
|
||||
static char *
|
||||
dtrace_json(uint64_t size, uintptr_t json, char *elemlist, int nelems,
|
||||
char *dest)
|
||||
{
|
||||
dtrace_json_state_t state = DTRACE_JSON_REST;
|
||||
int64_t array_elem = INT64_MIN;
|
||||
int64_t array_pos = 0;
|
||||
uint8_t escape_unicount = 0;
|
||||
boolean_t string_is_key = B_FALSE;
|
||||
boolean_t collect_object = B_FALSE;
|
||||
boolean_t found_key = B_FALSE;
|
||||
boolean_t in_array = B_FALSE;
|
||||
uint32_t braces = 0, brackets = 0;
|
||||
char *elem = elemlist;
|
||||
char *dd = dest;
|
||||
uintptr_t cur;
|
||||
|
||||
for (cur = json; cur < json + size; cur++) {
|
||||
char cc = dtrace_load8(cur);
|
||||
if (cc == '\0')
|
||||
return (NULL);
|
||||
|
||||
switch (state) {
|
||||
case DTRACE_JSON_REST:
|
||||
if (isspace(cc))
|
||||
break;
|
||||
|
||||
if (cc == '{') {
|
||||
state = DTRACE_JSON_OBJECT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cc == '[') {
|
||||
in_array = B_TRUE;
|
||||
array_pos = 0;
|
||||
array_elem = dtrace_strtoll(elem, 10, size);
|
||||
found_key = array_elem == 0 ? B_TRUE : B_FALSE;
|
||||
state = DTRACE_JSON_VALUE;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* ERROR: expected to find a top-level object or array.
|
||||
*/
|
||||
return (NULL);
|
||||
case DTRACE_JSON_OBJECT:
|
||||
if (isspace(cc))
|
||||
break;
|
||||
|
||||
if (cc == '"') {
|
||||
state = DTRACE_JSON_STRING;
|
||||
string_is_key = B_TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* ERROR: either the object did not start with a key
|
||||
* string, or we've run off the end of the object
|
||||
* without finding the requested key.
|
||||
*/
|
||||
return (NULL);
|
||||
case DTRACE_JSON_STRING:
|
||||
if (cc == '\\') {
|
||||
*dd++ = '\\';
|
||||
state = DTRACE_JSON_STRING_ESCAPE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cc == '"') {
|
||||
if (collect_object) {
|
||||
/*
|
||||
* We don't reset the dest here, as
|
||||
* the string is part of a larger
|
||||
* object being collected.
|
||||
*/
|
||||
*dd++ = cc;
|
||||
collect_object = B_FALSE;
|
||||
state = DTRACE_JSON_COLLECT_OBJECT;
|
||||
break;
|
||||
}
|
||||
*dd = '\0';
|
||||
dd = dest; /* reset string buffer */
|
||||
if (string_is_key) {
|
||||
if (dtrace_strncmp(dest, elem,
|
||||
size) == 0)
|
||||
found_key = B_TRUE;
|
||||
} else if (found_key) {
|
||||
if (nelems > 1) {
|
||||
/*
|
||||
* We expected an object, not
|
||||
* this string.
|
||||
*/
|
||||
return (NULL);
|
||||
}
|
||||
return (dest);
|
||||
}
|
||||
state = string_is_key ? DTRACE_JSON_COLON :
|
||||
DTRACE_JSON_COMMA;
|
||||
string_is_key = B_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
*dd++ = cc;
|
||||
break;
|
||||
case DTRACE_JSON_STRING_ESCAPE:
|
||||
*dd++ = cc;
|
||||
if (cc == 'u') {
|
||||
escape_unicount = 0;
|
||||
state = DTRACE_JSON_STRING_ESCAPE_UNICODE;
|
||||
} else {
|
||||
state = DTRACE_JSON_STRING;
|
||||
}
|
||||
break;
|
||||
case DTRACE_JSON_STRING_ESCAPE_UNICODE:
|
||||
if (!isxdigit(cc)) {
|
||||
/*
|
||||
* ERROR: invalid unicode escape, expected
|
||||
* four valid hexidecimal digits.
|
||||
*/
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
*dd++ = cc;
|
||||
if (++escape_unicount == 4)
|
||||
state = DTRACE_JSON_STRING;
|
||||
break;
|
||||
case DTRACE_JSON_COLON:
|
||||
if (isspace(cc))
|
||||
break;
|
||||
|
||||
if (cc == ':') {
|
||||
state = DTRACE_JSON_VALUE;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* ERROR: expected a colon.
|
||||
*/
|
||||
return (NULL);
|
||||
case DTRACE_JSON_COMMA:
|
||||
if (isspace(cc))
|
||||
break;
|
||||
|
||||
if (cc == ',') {
|
||||
if (in_array) {
|
||||
state = DTRACE_JSON_VALUE;
|
||||
if (++array_pos == array_elem)
|
||||
found_key = B_TRUE;
|
||||
} else {
|
||||
state = DTRACE_JSON_OBJECT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* ERROR: either we hit an unexpected character, or
|
||||
* we reached the end of the object or array without
|
||||
* finding the requested key.
|
||||
*/
|
||||
return (NULL);
|
||||
case DTRACE_JSON_IDENTIFIER:
|
||||
if (islower(cc)) {
|
||||
*dd++ = cc;
|
||||
break;
|
||||
}
|
||||
|
||||
*dd = '\0';
|
||||
dd = dest; /* reset string buffer */
|
||||
|
||||
if (dtrace_strncmp(dest, "true", 5) == 0 ||
|
||||
dtrace_strncmp(dest, "false", 6) == 0 ||
|
||||
dtrace_strncmp(dest, "null", 5) == 0) {
|
||||
if (found_key) {
|
||||
if (nelems > 1) {
|
||||
/*
|
||||
* ERROR: We expected an object,
|
||||
* not this identifier.
|
||||
*/
|
||||
return (NULL);
|
||||
}
|
||||
return (dest);
|
||||
} else {
|
||||
cur--;
|
||||
state = DTRACE_JSON_COMMA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ERROR: we did not recognise the identifier as one
|
||||
* of those in the JSON specification.
|
||||
*/
|
||||
return (NULL);
|
||||
case DTRACE_JSON_NUMBER:
|
||||
if (cc == '.') {
|
||||
*dd++ = cc;
|
||||
state = DTRACE_JSON_NUMBER_FRAC;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cc == 'x' || cc == 'X') {
|
||||
/*
|
||||
* ERROR: specification explicitly excludes
|
||||
* hexidecimal or octal numbers.
|
||||
*/
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* FALLTHRU */
|
||||
case DTRACE_JSON_NUMBER_FRAC:
|
||||
if (cc == 'e' || cc == 'E') {
|
||||
*dd++ = cc;
|
||||
state = DTRACE_JSON_NUMBER_EXP;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cc == '+' || cc == '-') {
|
||||
/*
|
||||
* ERROR: expect sign as part of exponent only.
|
||||
*/
|
||||
return (NULL);
|
||||
}
|
||||
/* FALLTHRU */
|
||||
case DTRACE_JSON_NUMBER_EXP:
|
||||
if (isdigit(cc) || cc == '+' || cc == '-') {
|
||||
*dd++ = cc;
|
||||
break;
|
||||
}
|
||||
|
||||
*dd = '\0';
|
||||
dd = dest; /* reset string buffer */
|
||||
if (found_key) {
|
||||
if (nelems > 1) {
|
||||
/*
|
||||
* ERROR: We expected an object, not
|
||||
* this number.
|
||||
*/
|
||||
return (NULL);
|
||||
}
|
||||
return (dest);
|
||||
}
|
||||
|
||||
cur--;
|
||||
state = DTRACE_JSON_COMMA;
|
||||
break;
|
||||
case DTRACE_JSON_VALUE:
|
||||
if (isspace(cc))
|
||||
break;
|
||||
|
||||
if (cc == '{' || cc == '[') {
|
||||
if (nelems > 1 && found_key) {
|
||||
in_array = cc == '[' ? B_TRUE : B_FALSE;
|
||||
/*
|
||||
* If our element selector directs us
|
||||
* to descend into this nested object,
|
||||
* then move to the next selector
|
||||
* element in the list and restart the
|
||||
* state machine.
|
||||
*/
|
||||
while (*elem != '\0')
|
||||
elem++;
|
||||
elem++; /* skip the inter-element NUL */
|
||||
nelems--;
|
||||
dd = dest;
|
||||
if (in_array) {
|
||||
state = DTRACE_JSON_VALUE;
|
||||
array_pos = 0;
|
||||
array_elem = dtrace_strtoll(
|
||||
elem, 10, size);
|
||||
found_key = array_elem == 0 ?
|
||||
B_TRUE : B_FALSE;
|
||||
} else {
|
||||
found_key = B_FALSE;
|
||||
state = DTRACE_JSON_OBJECT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, we wish to either skip this
|
||||
* nested object or return it in full.
|
||||
*/
|
||||
if (cc == '[')
|
||||
brackets = 1;
|
||||
else
|
||||
braces = 1;
|
||||
*dd++ = cc;
|
||||
state = DTRACE_JSON_COLLECT_OBJECT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cc == '"') {
|
||||
state = DTRACE_JSON_STRING;
|
||||
break;
|
||||
}
|
||||
|
||||
if (islower(cc)) {
|
||||
/*
|
||||
* Here we deal with true, false and null.
|
||||
*/
|
||||
*dd++ = cc;
|
||||
state = DTRACE_JSON_IDENTIFIER;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cc == '-' || isdigit(cc)) {
|
||||
*dd++ = cc;
|
||||
state = DTRACE_JSON_NUMBER;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* ERROR: unexpected character at start of value.
|
||||
*/
|
||||
return (NULL);
|
||||
case DTRACE_JSON_COLLECT_OBJECT:
|
||||
if (cc == '\0')
|
||||
/*
|
||||
* ERROR: unexpected end of input.
|
||||
*/
|
||||
return (NULL);
|
||||
|
||||
*dd++ = cc;
|
||||
if (cc == '"') {
|
||||
collect_object = B_TRUE;
|
||||
state = DTRACE_JSON_STRING;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cc == ']') {
|
||||
if (brackets-- == 0) {
|
||||
/*
|
||||
* ERROR: unbalanced brackets.
|
||||
*/
|
||||
return (NULL);
|
||||
}
|
||||
} else if (cc == '}') {
|
||||
if (braces-- == 0) {
|
||||
/*
|
||||
* ERROR: unbalanced braces.
|
||||
*/
|
||||
return (NULL);
|
||||
}
|
||||
} else if (cc == '{') {
|
||||
braces++;
|
||||
} else if (cc == '[') {
|
||||
brackets++;
|
||||
}
|
||||
|
||||
if (brackets == 0 && braces == 0) {
|
||||
if (found_key) {
|
||||
*dd = '\0';
|
||||
return (dest);
|
||||
}
|
||||
dd = dest; /* reset string buffer */
|
||||
state = DTRACE_JSON_COMMA;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Emulate the execution of DTrace ID subroutines invoked by the call opcode.
|
||||
* Notice that we don't bother validating the proper number of arguments or
|
||||
@ -4265,6 +4775,65 @@ dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
|
||||
break;
|
||||
}
|
||||
|
||||
case DIF_SUBR_JSON: {
|
||||
uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
|
||||
uintptr_t json = tupregs[0].dttk_value;
|
||||
size_t jsonlen = dtrace_strlen((char *)json, size);
|
||||
uintptr_t elem = tupregs[1].dttk_value;
|
||||
size_t elemlen = dtrace_strlen((char *)elem, size);
|
||||
|
||||
char *dest = (char *)mstate->dtms_scratch_ptr;
|
||||
char *elemlist = (char *)mstate->dtms_scratch_ptr + jsonlen + 1;
|
||||
char *ee = elemlist;
|
||||
int nelems = 1;
|
||||
uintptr_t cur;
|
||||
|
||||
if (!dtrace_canload(json, jsonlen + 1, mstate, vstate) ||
|
||||
!dtrace_canload(elem, elemlen + 1, mstate, vstate)) {
|
||||
regs[rd] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!DTRACE_INSCRATCH(mstate, jsonlen + 1 + elemlen + 1)) {
|
||||
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
|
||||
regs[rd] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the element selector and split it up into a packed list
|
||||
* of strings.
|
||||
*/
|
||||
for (cur = elem; cur < elem + elemlen; cur++) {
|
||||
char cc = dtrace_load8(cur);
|
||||
|
||||
if (cur == elem && cc == '[') {
|
||||
/*
|
||||
* If the first element selector key is
|
||||
* actually an array index then ignore the
|
||||
* bracket.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cc == ']')
|
||||
continue;
|
||||
|
||||
if (cc == '.' || cc == '[') {
|
||||
nelems++;
|
||||
cc = '\0';
|
||||
}
|
||||
|
||||
*ee++ = cc;
|
||||
}
|
||||
*ee++ = '\0';
|
||||
|
||||
if ((regs[rd] = (uintptr_t)dtrace_json(size, json, elemlist,
|
||||
nelems, dest)) != 0)
|
||||
mstate->dtms_scratch_ptr += jsonlen + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case DIF_SUBR_TOUPPER:
|
||||
case DIF_SUBR_TOLOWER: {
|
||||
uintptr_t s = tupregs[0].dttk_value;
|
||||
@ -4574,6 +5143,28 @@ dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
|
||||
break;
|
||||
}
|
||||
|
||||
case DIF_SUBR_STRTOLL: {
|
||||
uintptr_t s = tupregs[0].dttk_value;
|
||||
uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
|
||||
int base = 10;
|
||||
|
||||
if (nargs > 1) {
|
||||
if ((base = tupregs[1].dttk_value) <= 1 ||
|
||||
base > ('z' - 'a' + 1) + ('9' - '0' + 1)) {
|
||||
*flags |= CPU_DTRACE_ILLOP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dtrace_strcanload(s, size, mstate, vstate)) {
|
||||
regs[rd] = INT64_MIN;
|
||||
break;
|
||||
}
|
||||
|
||||
regs[rd] = dtrace_strtoll((char *)s, base, size);
|
||||
break;
|
||||
}
|
||||
|
||||
case DIF_SUBR_LLTOSTR: {
|
||||
int64_t i = (int64_t)tupregs[0].dttk_value;
|
||||
uint64_t val, digit;
|
||||
@ -9373,7 +9964,9 @@ dtrace_difo_validate_helper(dtrace_difo_t *dp)
|
||||
subr == DIF_SUBR_INET_NTOA ||
|
||||
subr == DIF_SUBR_INET_NTOA6 ||
|
||||
subr == DIF_SUBR_INET_NTOP ||
|
||||
subr == DIF_SUBR_JSON ||
|
||||
subr == DIF_SUBR_LLTOSTR ||
|
||||
subr == DIF_SUBR_STRTOLL ||
|
||||
subr == DIF_SUBR_RINDEX ||
|
||||
subr == DIF_SUBR_STRCHR ||
|
||||
subr == DIF_SUBR_STRJOIN ||
|
||||
|
@ -313,7 +313,9 @@ typedef enum dtrace_probespec {
|
||||
#define DIF_SUBR_SX_ISEXCLUSIVE 50
|
||||
#define DIF_SUBR_MEMSTR 51
|
||||
#define DIF_SUBR_GETF 52
|
||||
#define DIF_SUBR_MAX 52 /* max subroutine value */
|
||||
#define DIF_SUBR_JSON 53
|
||||
#define DIF_SUBR_STRTOLL 54
|
||||
#define DIF_SUBR_MAX 54 /* max subroutine value */
|
||||
|
||||
typedef uint32_t dif_instr_t;
|
||||
|
||||
|
@ -4,6 +4,8 @@ SYSDIR?= ${.CURDIR}/../../..
|
||||
|
||||
ARCHDIR= ${MACHINE_CPUARCH}
|
||||
|
||||
SUNW= ${.CURDIR}/../../../../cddl/contrib/opensolaris
|
||||
|
||||
.PATH: ${SYSDIR}/cddl/contrib/opensolaris/uts/common/dtrace
|
||||
.PATH: ${SYSDIR}/cddl/compat/opensolaris/kern
|
||||
.PATH: ${SYSDIR}/cddl/kern
|
||||
@ -20,7 +22,8 @@ SRCS= dtrace.c \
|
||||
SRCS+= dis_tables.c \
|
||||
instr_size.c
|
||||
CFLAGS+= -I${SYSDIR}/cddl/contrib/opensolaris/uts/intel \
|
||||
-I${SYSDIR}/cddl/dev/dtrace/x86
|
||||
-I${SYSDIR}/cddl/dev/dtrace/x86 \
|
||||
-I${SUNW}/common/util
|
||||
.endif
|
||||
|
||||
SRCS+= bus_if.h device_if.h vnode_if.h
|
||||
|
Loading…
Reference in New Issue
Block a user