diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.subr.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.subr.d index c76cecf494b5..9b02e982fe0d 100644 --- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.subr.d +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/aggs/tst.subr.d @@ -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/ diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.general.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.general.d new file mode 100644 index 000000000000..4600811d95b9 --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.general.d @@ -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); +} diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.general.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.general.d.out new file mode 100644 index 000000000000..a857ab91d831 --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.general.d.out @@ -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>| + diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.strsize.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.strsize.d new file mode 100644 index 000000000000..6aa50b9ad02b --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.strsize.d @@ -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); +} diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.strsize.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.strsize.d.out new file mode 100644 index 000000000000..7f1d79b6fedb --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.strsize.d.out @@ -0,0 +1,13 @@ +|{"a": 1024| +<NULL> + +|{"a": 1024}| +1024 + +|{"a":false,"b":tru| +<NULL> + +|{"a":false,"b":20}| +20 + + diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.c new file mode 100644 index 000000000000..307106d903b5 --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.c @@ -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); +} diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.d new file mode 100644 index 000000000000..f0fbdd5cabab --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.d @@ -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); +} diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.d.out new file mode 100644 index 000000000000..c7f58bb535dd --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/tst.usdt.d.out @@ -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! + diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/usdt.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/usdt.d new file mode 100644 index 000000000000..1a4fc87f60f4 --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/json/usdt.d @@ -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); +}; diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.func_access.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.func_access.ksh index ae4934cdeb34..da9bb4c6c6b3 100644 --- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.func_access.ksh +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/privs/tst.func_access.ksh @@ -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++; } diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/err.BaseTooLarge.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/err.BaseTooLarge.d new file mode 100644 index 000000000000..4d6b5af75b55 --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/err.BaseTooLarge.d @@ -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); +} diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/err.BaseTooSmall.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/err.BaseTooSmall.d new file mode 100644 index 000000000000..de56b50e9eda --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/err.BaseTooSmall.d @@ -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); +} diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/tst.strtoll.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/tst.strtoll.d new file mode 100644 index 000000000000..0b1812a53ce0 --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/tst.strtoll.d @@ -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); +} diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/tst.strtoll.d.out b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/tst.strtoll.d.out new file mode 100644 index 000000000000..d12eb9c1973b --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/strtoll/tst.strtoll.d.out @@ -0,0 +1,20 @@ +0 +1 +32 +-32 +8 +42 +9223372036854775807 +-9223372036854775808 +9223372036854775807 +-9223372036854775808 +-9223372036854775808 +9223372036854775807 +3135097598 +12 +2 +-1819882045752187535 +1985 +-2012 +0 + diff --git a/cddl/contrib/opensolaris/common/util/strtolctype.h b/cddl/contrib/opensolaris/common/util/strtolctype.h new file mode 100644 index 000000000000..a1d18367d345 --- /dev/null +++ b/cddl/contrib/opensolaris/common/util/strtolctype.h @@ -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 */ diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c index 6a195016c4cd..92f3f27bae14 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c @@ -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, diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c index 8b35923868bc..e84b79cf18e4 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c +++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c @@ -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 || diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h index 2aedfeabc6ab..d7a705c65ff7 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h +++ b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h @@ -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; diff --git a/sys/modules/dtrace/dtrace/Makefile b/sys/modules/dtrace/dtrace/Makefile index ea2c1f1654aa..3a77390da8e3 100644 --- a/sys/modules/dtrace/dtrace/Makefile +++ b/sys/modules/dtrace/dtrace/Makefile @@ -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