Skip to content

Instantly share code, notes, and snippets.

@jclulow
Created November 9, 2012 11:02
Show Gist options
  • Select an option

  • Save jclulow/4045153 to your computer and use it in GitHub Desktop.

Select an option

Save jclulow/4045153 to your computer and use it in GitHub Desktop.
[root@ra ~]# ./json.d
BOOTING AT: Fri Nov 09 2012 18:00:50 GMT+0000 (UTC)
BOOTING AT: Fri Nov 09 2012 18:00:52 GMT+0000 (UTC)
BOOTING AT: Fri Nov 09 2012 18:00:53 GMT+0000 (UTC)
THE BOOT! 3
jacob 10
jingleheimer 10
schmidt 10
john 11
BOOTING AT: Fri Nov 09 2012 18:00:54 GMT+0000 (UTC)
BOOTING AT: Fri Nov 09 2012 18:00:56 GMT+0000 (UTC)
BOOTING AT: Fri Nov 09 2012 18:00:57 GMT+0000 (UTC)
BOOTING AT: Fri Nov 09 2012 18:00:58 GMT+0000 (UTC)
THE BOOT! 4
john 11
schmidt 11
jacob 12
jingleheimer 12
BOOTING AT: Fri Nov 09 2012 18:01:00 GMT+0000 (UTC)
BOOTING AT: Fri Nov 09 2012 18:01:01 GMT+0000 (UTC)
THE BOOT! 2
jacob 5
john 5
jingleheimer 6
schmidt 7
^C
#!/usr/sbin/dtrace -Zqs
jmcapp*:::awesome
{
this->j = copyinstr(arg0);
@[json(this->j, "name")] = count();
}
jmcapp*:::awesome
/json(this->j, "name") == "THE BOOT!"/
{
printf("BOOTING AT: %s\n", json(this->j, "date"));
}
tick-5s
{
printa(@);
clear(@);
}
var dtrace_provider = require('dtrace-provider');
var dtp = dtrace_provider.createDTraceProvider("jmcapp");
var awesome = dtp.addProbe("awesome", "char *");
dtp.enable();
var NAMES = ['john', 'jacob', 'jingleheimer', 'schmidt'];
var ii = 0;
setInterval(function() {
ii++;
var obj = {
date: Date() + '',
name: ii % 13 === 0 ? 'THE BOOT!' : NAMES[ii % NAMES.length]
};
awesome.fire(function(p) {
return [JSON.stringify(obj)];
});
}, 100);
diff --git a/usr/src/lib/libdtrace/common/dt_open.c b/usr/src/lib/libdtrace/common/dt_open.c
index a7f8676..e6027f4 100644
--- a/usr/src/lib/libdtrace/common/dt_open.c
+++ b/usr/src/lib/libdtrace/common/dt_open.c
@@ -263,6 +263,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_10,
+ &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,
diff --git a/usr/src/uts/common/dtrace/dtrace.c b/usr/src/uts/common/dtrace/dtrace.c
index 8ef84d1..8865fbd 100644
--- a/usr/src/uts/common/dtrace/dtrace.c
+++ b/usr/src/uts/common/dtrace/dtrace.c
@@ -464,6 +464,7 @@ dtrace_load##bits(uintptr_t addr) \
(act)->dta_difo->dtdo_rtype.dtdt_kind == DIF_TYPE_STRING)
static size_t dtrace_strlen(const char *, size_t);
+static int dtrace_streq(const char *, const char *, size_t);
static dtrace_probe_t *dtrace_probe_lookup_id(dtrace_id_t id);
static void dtrace_enabling_provide(dtrace_provider_t *);
static int dtrace_enabling_match(dtrace_enabling_t *, int *);
@@ -927,6 +928,25 @@ dtrace_strlen(const char *s, size_t lim)
return (len);
}
+static int
+dtrace_streq(const char *a, const char *b, size_t lim)
+{
+ uint_t len;
+
+ for (len = 0; len != lim; len++) {
+ char aa = dtrace_load8((uintptr_t)a++);
+ char bb = dtrace_load8((uintptr_t)b++);
+
+ if (aa != bb)
+ return (0);
+
+ if (aa == '\0')
+ return (1);
+ }
+
+ return (0);
+}
+
/*
* Check if an address falls within a toxic region.
*/
@@ -3353,6 +3373,167 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
}
}
+typedef enum json_state {
+ JSON_REST = 1,
+ JSON_OBJECT,
+ JSON_STRING,
+ JSON_STRING_ESCAPE,
+ JSON_COLON,
+ JSON_COMMA,
+ JSON_VALUE,
+ JSON_COLLECT_OBJECT
+} json_state_t;
+
+static char *
+dtrace_json(uint64_t size, uintptr_t json, uintptr_t elem, char *dest)
+{
+ json_state_t state = JSON_REST;
+ uintptr_t cur = json;
+ uint64_t i;
+ uint8_t string_is_key = 0;
+ uint8_t collect_object = 0;
+ uint8_t found_key = 0;
+ uint8_t braces = 0;
+ char *dd = dest;
+
+ for (cur = json; cur < json + size; cur++) {
+ char cc = dtrace_load8(cur);
+ if (cc == '\0' || braces > 250)
+ return (NULL);
+
+ switch (state) {
+ case JSON_REST:
+ if (cc == ' ' || cc == '\t')
+ break; /* eat whitespace */
+
+ if (cc == '{') {
+ state = JSON_OBJECT;
+ break;
+ }
+
+ /* XXX ERROR: unexpected object */
+ return (NULL);
+ case JSON_OBJECT:
+ if (cc == ' ' || cc == '\t')
+ break; /* eat whitespace */
+
+ if (cc == '"') {
+ state = JSON_STRING;
+ string_is_key = 1;
+ break;
+ }
+
+ /* XXX ERROR: key not found! */
+ return (NULL);
+ case JSON_STRING:
+ if (cc == '\\') {
+ state = 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 = 0;
+ state = JSON_COLLECT_OBJECT;
+ break;
+ }
+ *dd = '\0';
+ dd = dest; /* reset string buffer */
+ if (string_is_key) {
+ if (dtrace_streq(dest, (char *)elem,
+ size))
+ found_key = 1;
+ } else if (found_key) {
+ return (dest);
+ }
+ state = string_is_key ? JSON_COLON :
+ JSON_COMMA;
+ string_is_key = 0;
+ break;
+ }
+
+ *dd++ = cc;
+ break;
+ case JSON_STRING_ESCAPE:
+ /* XXX handle \u0000 */
+ /* XXX should actually *escape* things? */
+ *dd++ = '\\';
+ *dd++ = cc;
+ state = JSON_STRING;
+ break;
+ case JSON_COLON:
+ if (cc == ' ' || cc == '\t')
+ break; /* eat whitespace */
+
+ if (cc == ':') {
+ state = JSON_VALUE;
+ break;
+ }
+
+ /* XXX ERROR: expected colon */
+ return (NULL);
+ case JSON_COMMA:
+ if (cc == ' ' || cc == '\t')
+ break; /* eat whitespace */
+
+ if (cc == ',') {
+ state = JSON_OBJECT;
+ break;
+ }
+
+ /*XXX ERROR: key not found or expected comma */
+ return (NULL);
+ case JSON_VALUE:
+ if (cc == ' ' || cc == '\t')
+ break; /* eat whitespace */
+
+ if (cc == '{') {
+ *dd++ = cc;
+ state = JSON_COLLECT_OBJECT;
+ braces = 1;
+ break;
+ }
+
+ if (cc == '"') {
+ state = JSON_STRING;
+ break;
+ }
+
+ /*
+ * XXX ERROR: should handle types
+ * other than STRING or OBJECT
+ */
+ return (NULL);
+ case JSON_COLLECT_OBJECT:
+ if (cc == '\0')
+ /* ERROR: unexpected end! */
+ return (NULL);
+ *dd++ = cc;
+ if (cc == '"') {
+ collect_object = 1;
+ state = JSON_STRING;
+ } else if (cc == '}') {
+ if (found_key) {
+ *dd = '\0';
+ return (dest);
+ }
+ if (--braces == 0)
+ state = JSON_COMMA;
+ } else if (cc == '{') {
+ braces++;
+ }
+ 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
@@ -4053,6 +4234,32 @@ dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
break;
}
+ case DIF_SUBR_JSON: {
+ uintptr_t json = tupregs[0].dttk_value;
+ uintptr_t elem = tupregs[1].dttk_value;
+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
+ char *dest = (char *)mstate->dtms_scratch_ptr;
+ size_t jsonlen = dtrace_strlen((char *)json, size);
+ size_t elemlen = dtrace_strlen((char *)elem, size);
+
+ if (!dtrace_canload(json, jsonlen + 1, mstate, vstate) ||
+ !dtrace_canload(elem, elemlen + 1, mstate, vstate)) {
+ regs[rd] = NULL;
+ break;
+ }
+
+ if (!DTRACE_INSCRATCH(mstate, size)) {
+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
+ regs[rd] = NULL;
+ break;
+ }
+
+ if ((regs[rd] = (uintptr_t)dtrace_json(size, json, elem,
+ dest)) != NULL)
+ mstate->dtms_scratch_ptr += size;
+ break;
+ }
+
case DIF_SUBR_TOUPPER:
case DIF_SUBR_TOLOWER: {
uintptr_t s = tupregs[0].dttk_value;
diff --git a/usr/src/uts/common/sys/dtrace.h b/usr/src/uts/common/sys/dtrace.h
index e6d9e0e..3267968 100644
--- a/usr/src/uts/common/sys/dtrace.h
+++ b/usr/src/uts/common/sys/dtrace.h
@@ -289,8 +289,9 @@ extern "C" {
#define DIF_SUBR_TOUPPER 44
#define DIF_SUBR_TOLOWER 45
#define DIF_SUBR_GETF 46
+#define DIF_SUBR_JSON 47
-#define DIF_SUBR_MAX 46 /* max subroutine value */
+#define DIF_SUBR_MAX 47 /* max subroutine value */
typedef uint32_t dif_instr_t;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment