Re: [PATCH] examples: Add "language features" demo scripts
Ruud van der Pas <[email protected]>
| Newsgroups | dev.linux.lists.dtrace |
|---|---|
| Message-ID | <[email protected]> |
Reviewed-by: Ruud van der Pas <[email protected]> > On 2 Sep 2025, at 22:02, [email protected] wrote: > > From: Eugene Loh <[email protected]> > > The idea is to have lots of short scripts, each illustrating a > D language feature. > > The numbering scheme serves two purposes: > > *) the scripts are more or less in ascending order > of difficulty, although that's admittedly a tricky > concept in such a multi-dimensional space > > *) there is some grouping of themes -- e.g., > "introduction", "providers", "built-in variables", etc. > > The combination of comments and code is intended to help either > a human user or an AI bot to learn how to use the D language. > > Other examples have been based on functional objectives (doing > simple but useful tasks). These new examples are based on language > features. A future set of examples could be based on errors! That > is, the scripts generate errors of different sorts that we would > illustrate (and explain how to fix). > > Signed-off-by: Eugene Loh <[email protected]> > --- > examples/README.md | 13 +++ > .../language_features/000intro-hello-world.d | 63 ++++++++++++ > .../language_features/001intro-ERROR-probe.d | 30 ++++++ > .../002intro-global-variables.d | 31 ++++++ > examples/language_features/003intro-C-like.d | 75 +++++++++++++++ > examples/language_features/004intro-ternary.d | 32 +++++++ > examples/language_features/005intro-strings.d | 65 +++++++++++++ > .../language_features/006intro-associative.d | 34 +++++++ > .../007intro-this-variables.d | 49 ++++++++++ > .../008intro-self-variables.d | 57 +++++++++++ > examples/language_features/009intro-pragmas.d | 38 ++++++++ > .../010intro-external-variables.d | 53 +++++++++++ > .../language_features/011intro-preprocessor.d | 25 +++++ > .../language_features/012intro-predicates.d | 52 ++++++++++ > examples/language_features/100list_probes.sh | 11 +++ > .../101count_probes_by_provider.sh | 12 +++ > .../102list_probe_arguments.sh | 11 +++ > .../language_features/110provider_profile.d | 29 ++++++ > examples/language_features/120provider_proc.d | 37 ++++++++ > .../130provider_sched_on_off_cpu.d | 28 ++++++ > .../131provider_sched_enqueue_dequeue.d | 24 +++++ > .../language_features/140provider_syscall.d | 20 ++++ > examples/language_features/150provider_fbt.d | 48 ++++++++++ > .../160provider_sdt_rawtp.sh | 36 +++++++ > .../language_features/170provider_lockstat.sh | 17 ++++ > examples/language_features/171provider_io.d | 31 ++++++ > examples/language_features/172provider_ip.d | 26 +++++ > examples/language_features/180provider_cpc.d | 52 ++++++++++ > .../200built-in-variables-probe.d | 18 ++++ > .../201built-in-variables-timestamps.d | 31 ++++++ > .../202built-in-variables-args.d | 28 ++++++ > .../203built-in-variables-process-info.d | 31 ++++++ > .../204built-in-variables-uregs.d | 31 ++++++ > examples/language_features/300actions-exit.sh | 18 ++++ > examples/language_features/301actions-print.d | 32 +++++++ > .../language_features/302actions-strings.d | 45 +++++++++ > .../303actions-strings-paths.d | 25 +++++ > .../language_features/304actions-system.d | 22 +++++ > .../language_features/305actions-progenyof.d | 20 ++++ > .../306actions-speculations.d | 57 +++++++++++ > .../language_features/307actions-callstack.d | 54 +++++++++++ > .../310actions-alloca-copy.d | 95 +++++++++++++++++++ > examples/language_features/311actions-rand.d | 25 +++++ > .../language_features/500aggregations-intro.d | 24 +++++ > .../501aggregations-names-keys.d | 19 ++++ > .../502aggregations-basic-funcs.d | 26 +++++ > .../language_features/503aggregations-stack.d | 24 +++++ > .../504aggregations-printa.d | 29 ++++++ > .../505aggregations-quantize.d | 65 +++++++++++++ > .../506aggregations-clear-trunc.d | 63 ++++++++++++ > .../507aggregations-trunc5.d | 50 ++++++++++ > .../508aggregations-normalize.d | 49 ++++++++++ > 52 files changed, 1880 insertions(+) > create mode 100755 examples/language_features/000intro-hello-world.d > create mode 100755 examples/language_features/001intro-ERROR-probe.d > create mode 100755 examples/language_features/002intro-global-variables.d > create mode 100755 examples/language_features/003intro-C-like.d > create mode 100755 examples/language_features/004intro-ternary.d > create mode 100755 examples/language_features/005intro-strings.d > create mode 100755 examples/language_features/006intro-associative.d > create mode 100755 examples/language_features/007intro-this-variables.d > create mode 100755 examples/language_features/008intro-self-variables.d > create mode 100755 examples/language_features/009intro-pragmas.d > create mode 100755 examples/language_features/010intro-external-variables.d > create mode 100755 examples/language_features/011intro-preprocessor.d > create mode 100755 examples/language_features/012intro-predicates.d > create mode 100755 examples/language_features/100list_probes.sh > create mode 100755 examples/language_features/101count_probes_by_provider.sh > create mode 100755 examples/language_features/102list_probe_arguments.sh > create mode 100755 examples/language_features/110provider_profile.d > create mode 100755 examples/language_features/120provider_proc.d > create mode 100755 examples/language_features/130provider_sched_on_off_cpu.d > create mode 100755 examples/language_features/131provider_sched_enqueue_dequeue.d > create mode 100755 examples/language_features/140provider_syscall.d > create mode 100755 examples/language_features/150provider_fbt.d > create mode 100755 examples/language_features/160provider_sdt_rawtp.sh > create mode 100755 examples/language_features/170provider_lockstat.sh > create mode 100755 examples/language_features/171provider_io.d > create mode 100755 examples/language_features/172provider_ip.d > create mode 100755 examples/language_features/180provider_cpc.d > create mode 100755 examples/language_features/200built-in-variables-probe.d > create mode 100755 examples/language_features/201built-in-variables-timestamps.d > create mode 100755 examples/language_features/202built-in-variables-args.d > create mode 100755 examples/language_features/203built-in-variables-process-info.d > create mode 100755 examples/language_features/204built-in-variables-uregs.d > create mode 100755 examples/language_features/300actions-exit.sh > create mode 100755 examples/language_features/301actions-print.d > create mode 100755 examples/language_features/302actions-strings.d > create mode 100755 examples/language_features/303actions-strings-paths.d > create mode 100755 examples/language_features/304actions-system.d > create mode 100755 examples/language_features/305actions-progenyof.d > create mode 100755 examples/language_features/306actions-speculations.d > create mode 100755 examples/language_features/307actions-callstack.d > create mode 100755 examples/language_features/310actions-alloca-copy.d > create mode 100755 examples/language_features/311actions-rand.d > create mode 100755 examples/language_features/500aggregations-intro.d > create mode 100755 examples/language_features/501aggregations-names-keys.d > create mode 100755 examples/language_features/502aggregations-basic-funcs.d > create mode 100755 examples/language_features/503aggregations-stack.d > create mode 100755 examples/language_features/504aggregations-printa.d > create mode 100755 examples/language_features/505aggregations-quantize.d > create mode 100755 examples/language_features/506aggregations-clear-trunc.d > create mode 100755 examples/language_features/507aggregations-trunc5.d > create mode 100755 examples/language_features/508aggregations-normalize.d > > diff --git a/examples/README.md b/examples/README.md > index de4ba090b..b84a34031 100644 > --- a/examples/README.md > +++ b/examples/README.md > @@ -86,3 +86,16 @@ These are the scripts included, plus a brief description. > | | thread ID as returned in the DTrace tid variable. | > | var-scope.d | Demonstrate some of the scoping rules for global and |B| > | | clause-local variables. | > + > +## Language-feature examples > + > +In the language_features/ subdirectory are short scripts, > +each illustrating a D language feature. > + > +The numbering scheme serves two purposes: > + > +* The scripts are more or less in ascending order of difficulty, although that's admittedly a tricky concept in such a multi-dimensional space > + > +* There is some grouping of themes -- e.g., "introduction", "providers", "built-in variables", etc. > + > +The scripts start at Beginner, and they arguably do not get much more complicated than that. > diff --git a/examples/language_features/000intro-hello-world.d b/examples/language_features/000intro-hello-world.d > new file mode 100755 > index 000000000..a38f7cacc > --- /dev/null > +++ b/examples/language_features/000intro-hello-world.d > @@ -0,0 +1,63 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./000intro-hello-world.d > + * > + * or > + * > + * sudo /usr/sbin/dtrace -s 000intro-hello-world.d > + * > + * or > + * > + * sudo /usr/sbin/dtrace -n 'dtrace:::BEGIN > + * { > + * printf("hello world\n"); > + * exit(0); > + * } > + * dtrace:::END > + * { > + * trace("goodbye world"); > + * }' > + * > + * DESCRIPTION > + * This is a simple "hello world" program in D. It > + * illustrates a variety of very simple features of D. > + */ > + > +/* > + * The BEGIN probe fires when the script is launched. It can > + * be called by simply asking for BEGIN. Or, its provider can > + * also be named: dtrace:::BEGIN. The other probe description > + * fields, the module and function, are blank for this probe. > + */ > +dtrace:::BEGIN > +{ > + /* > + * A C-like printf() function can be used to print > + * data. Alternatively, the trace() function can be > + * used, and it will discern the appropriate data type. > + */ > + printf("hello world\n"); > + > + /* > + * Variables can be assigned. They maybe typed implicitly. > + */ > + x = 123; > + > + exit(0); > +} > + > +dtrace:::BEGIN > +/x == 456/ /* A predicate can indicate whether to execute a clause. */ > +{ > + trace("YOU SHOULD NOT SEE THIS MESSAGE!!!\n"); > +} > + > +/* > + * We can also gives actions to list at the end. > + */ > +dtrace:::END > +{ > + trace("goodbye world"); > +} > diff --git a/examples/language_features/001intro-ERROR-probe.d b/examples/language_features/001intro-ERROR-probe.d > new file mode 100755 > index 000000000..3c3a50eee > --- /dev/null > +++ b/examples/language_features/001intro-ERROR-probe.d > @@ -0,0 +1,30 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./001intro-ERROR-probe.d > + * > + * DESCRIPTION > + * The ERROR probe can be used to handle run-time errors. > + * If a clause encounters an error, its output is not seen > + * and the ERROR probe is triggered. Other clauses associated > + * with the guilty probe, however, do execute. > + */ > + > +dtrace:::ERROR > +{ > + printf("An error occurred.\n"); > +} > + > +dtrace:::BEGIN > +{ > + printf("WE SHOULD NOT SEE THIS!\n"); > + printf("Dereference an illegal address: %d\n", *((int *)0x1234)); > + printf("WE SHOULD NOT GET HERE!\n"); > +} > + > +dtrace:::BEGIN > +{ > + printf("This is a different clause.\n"); > + exit(0); > +} > diff --git a/examples/language_features/002intro-global-variables.d b/examples/language_features/002intro-global-variables.d > new file mode 100755 > index 000000000..9b9ec6533 > --- /dev/null > +++ b/examples/language_features/002intro-global-variables.d > @@ -0,0 +1,31 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./002intro-global-variables.d > + * > + * DESCRIPTION > + * Rules for variable names are similar to those in C. By > + * default, they are "global" -- that is, seen by every thread > + * and every probe. So be careful that no thread overwrites any > + * other thread's write. Variables may be typed implicitly. > + */ > + > +int explicitly_typed_variable; > + > +dtrace:::BEGIN > +{ > + explicitly_typed_variable = 1234; > + implicitly_typed_variable = 5678; > + > + printf("%d %d\n", explicitly_typed_variable, > + implicitly_typed_variable); > + > + my_char = 'a'; > + my_string = "hello world"; > + my_pointer = (int *) 0x123456; > + > + printf("%c '%s' %p\n", my_char, my_string, my_pointer); > + > + exit(0); > +} > diff --git a/examples/language_features/003intro-C-like.d b/examples/language_features/003intro-C-like.d > new file mode 100755 > index 000000000..2e3ea8bde > --- /dev/null > +++ b/examples/language_features/003intro-C-like.d > @@ -0,0 +1,75 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./003intro-C-like.d > + * > + * DESCRIPTION > + * Much of D syntax is very C-like. Examples are shown here. > + * Check the documentation for more complete information. > + * > + * Differences include: > + * - D variables can be typed implicitly > + * - D has no "if" "switch" "case" "for" > + * - D has no function definitions > + */ > + > +/* > + * As you have already seen, one can use multi-line comments in D > + * similarly to C. > + */ > + > +/* > + * Variables can be declared explicitly. Data types like short, int, long, > + * long long, char, struct, and union are familiar from C. > + */ > +int x, y, arr[5]; > + > +dtrace:::BEGIN > +{ > + /* Assignments are similar to C. */ > + x = 1; > + y = 2; > + x += 3; > + > + /* There are familiar operators. E.g., arithmetic operators. */ > + x = x + y; > + y = 3 * x - 2 * y; > + > + /* Relational operators. */ > + x = 2 > 3; > + y = 2 >= 3; > + > + /* Logical operators. */ > + x = (2 > 3) && (2 >= 3); > + > + /* Bitwise operators. */ > + x = x & y; > + > + /* Various unary operators. */ > + x = x++ + --y; > + > + /* Types and casting. */ > + x = (long long) (sizeof(int) + ((int) 0xfedcba9876543210ull)); > + > + /* > + * In contrast with C, D has a printf() whose %d, %x, and %i format > + * conversions use type information about the corresponding argument > + * to interpret that argument with its actual word size. > + */ > + printf("%x\n", x); > + > + /* Arrays can also be associative. More on that later. */ > + arr[0] = 10000; > + arr[1] = 11111; > + arr[2] = 12222; > + arr[3] = 13333; > + arr[4] = 14444; > + > + /* One can get addresses and dereference addresses. */ > + /* (In this case, `nr_cpu_ids is a kernel variable.) */ > + ptr = &`nr_cpu_ids; > + printf("nr_cpu_ids: %d should equal %d\n", *ptr, `nr_cpu_ids); > + > + exit(0); > +} > diff --git a/examples/language_features/004intro-ternary.d b/examples/language_features/004intro-ternary.d > new file mode 100755 > index 000000000..e6404f8b6 > --- /dev/null > +++ b/examples/language_features/004intro-ternary.d > @@ -0,0 +1,32 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./004intro-ternary.d > + * > + * DESCRIPTION > + * Much of D syntax is very C-like. Another example is > + * ternary operations: ($condition ? $if_yes : $if_no). > + * In D, however, ternary operations are argubly more > + * useful than they are in C. The D language does not > + * have conditional constructs like "if" statements. > + * Therefore, other constructs, like predicates and > + * speculations, must be used. Or, ternary operations. > + */ > + > +dtrace:::BEGIN > +{ > + x = 123; > + y = 456; > + > + /* basic ternary operation to implement z = MIN(x, y) */ > + z = (x < y) ? x : y; > + > + /* a more novel use to conditionalize an assignment */ > + (x < y) ? (y = x) : 1; > + > + /* all three variables should have the same value */ > + printf("x = %d; y = %d; z = %d\n", x, y, z); > + > + exit(0); > +} > diff --git a/examples/language_features/005intro-strings.d b/examples/language_features/005intro-strings.d > new file mode 100755 > index 000000000..5a758fcc3 > --- /dev/null > +++ b/examples/language_features/005intro-strings.d > @@ -0,0 +1,65 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./005intro-strings.d > + * > + * DESCRIPTION > + * But D does differ from C when it comes to strings. > + * The D language has a built-in string data type. > + */ > + > +/* > + * Strings are stored in arrays of fixed length. The > + * default length 256 can be overridden with a D option. > + */ > +#pragma D option strsize=12 > + > +/* string variables can be declared explicitly */ > +string exp; > +string s1, s2, s3, s4; > + > +char carray[32]; > + > +BEGIN > +{ > + /* strings are truncated, if necessary, per strsize */ > + printf("%s\n", "abcdefghijklmnopqrstuvwxyz"); > + > + /* string variables can be declared implicitly */ > + imp = "abcdefghijklmnopqrstuvwxyz"; > + printf("%d chars, string %s\n", sizeof(imp), imp); > + > + /* operators can be used to order strings lexically (akin to strcmp) */ > + exp = "zyxwvutsrqponmlkjihgfedcba"; > + printf("%s is %s than %s\n", imp, imp < exp ? "less" : "greater", exp); > + > + /* set up NULL-terminated char array for some illustration purposes */ > + carray[ 0] = 'A'; carray[ 1] = 'B'; carray[ 2] = 'C'; carray[ 3] = 'D'; > + carray[ 4] = 'E'; carray[ 5] = 'F'; carray[ 6] = 'G'; carray[ 7] = 'H'; > + carray[ 8] = 'I'; carray[ 9] = 'J'; carray[10] = 'K'; carray[11] = 'L'; > + carray[12] = 'M'; carray[13] = 'N'; carray[14] = 'O'; carray[15] = 'P'; > + carray[16] = 'Q'; carray[17] = 'R'; carray[18] = 'S'; carray[19] = 'T'; > + carray[20] = 'U'; carray[21] = 'V'; carray[22] = 'W'; carray[23] = 'X'; > + carray[24] = 'Y'; carray[25] = 'Z'; carray[26] = '\0'; > + > + /* char pointers can be turned into strings */ > + s1 = (string) carray; /* type casting */ > + s2 = stringof carray; /* stringof operator */ > + > + /* char pointers can be promoted automatically to strings */ > + s3 = carray; > + s4 = strchr(carray, 'B'); > + > + /* > + * Note that in the above assignments, we did not simply set > + * a char* to some existing string buffer. Rather, contents > + * are copied "by-value" to the destination string buffer. > + * E.g., if the source buffer is modified, the output strings > + * nevertheless all stay the same. > + */ > + carray[2] = '\0'; > + printf("%s %s %s %s %s\n", s1, s2, s3, s4, carray); > + > + exit(0); > +} > diff --git a/examples/language_features/006intro-associative.d b/examples/language_features/006intro-associative.d > new file mode 100755 > index 000000000..b811c6028 > --- /dev/null > +++ b/examples/language_features/006intro-associative.d > @@ -0,0 +1,34 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./006intro-associative.d > + * > + * DESCRIPTION > + * The D language also supports associative arrays. > + */ > + > +/* associative arrays can be declared explicitly by key (if any) and value types */ > +int exp[string, int]; > + > +BEGIN > +{ > + /* associative arrays can also be declared implicitly */ > + imp["hello", 5] = 1234; > + > + /* values not set are assumed to be 0 */ > + printf("set value is %d; unset value is %d\n", > + imp["hello", 5], > + exp["hello", 5]); > + > + /* when you are done, set a value back to 0 to free the memory */ > + imp["hello", 5] = 0; > + > + /* > + * By the way, you cannot promote a char associative array > + * to a string -- whether with stringof or (string) -- since > + * it is not a consecutive block of memory holding chars in sequence. > + */ > + > + exit(0); > +} > diff --git a/examples/language_features/007intro-this-variables.d b/examples/language_features/007intro-this-variables.d > new file mode 100755 > index 000000000..4d9ba5390 > --- /dev/null > +++ b/examples/language_features/007intro-this-variables.d > @@ -0,0 +1,49 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./007intro-this-variables.d > + * > + * DESCRIPTION > + * We saw earlier that D supports global variables, allowing > + * convenient access from every probe and every thread. In > + * the same way, however, this causes the danger of different > + * probes and threads overwriting one another's values. > + * > + * For variables that are to used only within a set of clauses > + * for a specific probe, specify "this->". Such variables have > + * undefined values at the start of the set of clauses. > + */ > + > +/* "this" variables can be declared explicitly */ > +this int exp; > + > +dtrace:::BEGIN > +{ > + /* the value is undefined by default, define its value */ > + this->exp = 1234; > + > + /* variables can also be typed implicitly */ > + this->imp = 5678; > +} > + > +dtrace:::BEGIN > +/ 1 == 1 / > +{ > + /* the variables are available in this later clause for the same probe */ > + printf("%d %d\n", this->exp, this->imp); > + > + /* > + * There is no need to zero out this-> variables at the end of a > + * set of clauses: they will no longer exist anyhow and their > + * values when they are used in a different set of clauses, for > + * some other probe firing, will be undefined at first. > + */ > + > + exit(0); > +} > + > +END > +{ > + /* the variables are not available here, for a different probe */ > +} > diff --git a/examples/language_features/008intro-self-variables.d b/examples/language_features/008intro-self-variables.d > new file mode 100755 > index 000000000..68a5dcf59 > --- /dev/null > +++ b/examples/language_features/008intro-self-variables.d > @@ -0,0 +1,57 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./008intro-self-variables.d > + * > + * DESCRIPTION > + * In D, we can also have variables that are local to a thread. > + * We preface them with "self->". > + */ > + > +/* Thread-local "self" variables can be declared explicitly */ > +self int exp, dummy; > + > +syscall::write:entry > +{ > + /* we initialize one variable to the fd of the write() call */ > + self->exp = arg0; > + > + /* we can declare a self->variable implicitly, setting it to the requested number of bytes */ > + self->imp = arg2; > +} > + > +fbt::ksys_write:entry > +/ self->exp / > +{ > + self->kernel_value = arg2; > +} > + > +/* > + * We look for a write() return probe on the same thread where > + * self->exp has been set. Using thread-local variables allows > + * us to connect two probes for the same thread, without interference > + * from other threads. > + */ > +syscall::write:return > +/ self->exp / > +{ > + printf("on fd %d\n", self->exp); > + printf("bytes (requested): %d\n", self->imp); > + printf("bytes (requested in kernel function): %d\n", self->kernel_value); > + printf("bytes (actual): %d\n", arg1); > + > + /* uninitialized self-> variables are 0 */ > + printf("uninitialized is zero: %d\n", self->dummy); > + > + /* > + * It is good practice to zero out variables when you are > + * done with them to free up the associated memory. > + */ > + self->exp = 0; > + self->imp = 0; > + self->kernel_value = 0; > + > + /* but for this example, we are finished */ > + exit(0); > +} > diff --git a/examples/language_features/009intro-pragmas.d b/examples/language_features/009intro-pragmas.d > new file mode 100755 > index 000000000..a4e359976 > --- /dev/null > +++ b/examples/language_features/009intro-pragmas.d > @@ -0,0 +1,38 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./009intro-pragmas.d > + * > + * DESCRIPTION > + * D options can be set on the command line. E.g., > + * > + * sudo /usr/sbin/dtrace -xq ... > + * sudo /usr/sbin/dtrace -xw ... > + * sudo /usr/sbin/dtrace -xstrsize=12 ... > + * > + * They can also be set via pragmas inside a script. > + * Respectively, > + */ > + > +/* -q */ > +#pragma D option quiet > + > +/* -w, e.g., for the system() call */ > +#pragma D option destructive > + > +/* -xstrsize=12 */ > +#pragma D option strsize=12 > + > +/* > + * Simple options could alternatively be set on the first > + * "shebang" line. E.g., "#!/usr/sbin/dtrace -qws". > + */ > + > +dtrace:::BEGIN > +{ > + /* string truncated to strsize */ > + system("echo abcdefghijklmnopqrstuvwxyz"); > + > + exit(0); > +} > diff --git a/examples/language_features/010intro-external-variables.d b/examples/language_features/010intro-external-variables.d > new file mode 100755 > index 000000000..a763a36f6 > --- /dev/null > +++ b/examples/language_features/010intro-external-variables.d > @@ -0,0 +1,53 @@ > +#!/usr/sbin/dtrace -s > + > +#pragma D option quiet > +#pragma D option strsize=64 > + > +/* > + * SYNOPSIS > + * sudo ./010intro-external-variables.d > + * > + * DESCRIPTION > + * We can examine external variables -- that is, variables from outside > + * the D program, such as kernel variables. They are distinguished by > + * a back quote ` and constitute a different name space from that of > + * the D variables. When such a variables is named, the kernel and all > + * loaded modules are searched for the name. Or, you can specify a > + * module before the back quote. The kernel itself is module "vmlinux". > + * D scripts cannot modify values of kernel variables. > + * > + * Such external variables are not part of D and are subject to change. > + */ > + > +dtrace:::BEGIN > +{ > + > + printf("\n==== print some kernel variables ====\n\n"); > + > + printf("cad_pid->level: %d\n", ((struct pid *)`cad_pid)->level); > + printf("crashing_cpu: %d\n", `crashing_cpu); > + printf("linux_banner: %s\n", (string)`linux_banner); > + printf("linux_proc_banner: %s\n", (string)`linux_proc_banner); > + printf("load averages: %d.%02d, %d.%02d, %d.%02d\n", > + `avenrun[0] / 2048, ((`avenrun[0] % 2048) * 100) / 2048, > + `avenrun[1] / 2048, ((`avenrun[1] % 2048) * 100) / 2048, > + `avenrun[2] / 2048, ((`avenrun[2] % 2048) * 100) / 2048); > + printf("max_pvn: %d\n", `max_pfn); > + printf("nr_cpu_ids: %d\n", `nr_cpu_ids); > + printf("saved_command_line: %s\n", (string)`saved_command_line); > + > + printf("\n==== reprint some of them, explicitly naming vmlinux ====\n\n"); > + > + printf("crashing_cpu: %d\n", vmlinux`crashing_cpu); > + printf("linux_banner: %s\n", (string)vmlinux`linux_banner); > + printf("linux_proc_banner: %s\n", (string)vmlinux`linux_proc_banner); > + printf("max_pvn: %d\n", vmlinux`max_pfn); > + printf("nr_cpu_ids: %d\n", vmlinux`nr_cpu_ids); > + > + printf("\n==== refer to a data type in a module ====\n\n"); > + > + printf("offset of atomic in struct rds_message: %d\n", > + offsetof(struct rds`rds_message, atomic)); > + > + exit(0); > +} > diff --git a/examples/language_features/011intro-preprocessor.d b/examples/language_features/011intro-preprocessor.d > new file mode 100755 > index 000000000..1ece9d2d6 > --- /dev/null > +++ b/examples/language_features/011intro-preprocessor.d > @@ -0,0 +1,25 @@ > +#!/usr/sbin/dtrace -Cqs > + > +/* > + * SYNOPSIS > + * sudo ./011intro-preprocessor.d > + * > + * DESCRIPTION > + * D scripts can also use the C preprocessor. This requires using > + * the "dtrace -C" option, or by adding 'C' to the first, shebang > + * line, as illustrated above. > + */ > + > +#define KEYS "abcde", 12 > +#define DEBUG > + > +dtrace:::BEGIN > +{ > +#ifdef DEBUG > + printf("\nabcde, 12 should get a count of 1\n"); > +#endif > + > + @[KEYS] = count(); > + > + exit(0); > +} > diff --git a/examples/language_features/012intro-predicates.d b/examples/language_features/012intro-predicates.d > new file mode 100755 > index 000000000..3e4f7894d > --- /dev/null > +++ b/examples/language_features/012intro-predicates.d > @@ -0,0 +1,52 @@ > +#!/usr/sbin/dtrace -qs > + > +/* > + * SYNOPSIS > + * sudo ./012intro-predicates.d > + * > + * DESCRIPTION > + * We have already seen that predicates can be used to > + * conditionalize execution in a D scripts. (Other > + * mechanisms include speculation and ternary operators.) > + */ > + > +BEGIN > +{ > + ntimes = 0; > +} > + > +/* > + * The write() system call has a file descriptor in arg0 and a > + * requested number of bytes in arg2. If a nonzero number of > + * bytes is requested, take note of the fd. > + */ > +syscall::write:entry > +/ (self->nbytes_requested = arg2) != 0 / > +{ > + ntimes++; > + self->fd = arg0; > +} > + > +/* > + * When the write() system call returns, we know the actual > + * number of bytes written. Report it. > + */ > +syscall::write:return > +/ self->nbytes_requested != 0 / > +{ > + printf("fd %d: bytes requested %d, actual %d\n", > + self->fd, self->nbytes_requested, arg1); > + > + /* free memory associated with self-> variables */ > + self->nbytes_requested = 0; > + self->fd = 0; > +} > + > +/* > + * Only report a limited number of times. > + */ > +syscall::write:return > +/ ntimes >= 5 / > +{ > + exit(0); > +} > diff --git a/examples/language_features/100list_probes.sh b/examples/language_features/100list_probes.sh > new file mode 100755 > index 000000000..23bfd0525 > --- /dev/null > +++ b/examples/language_features/100list_probes.sh > @@ -0,0 +1,11 @@ > +#!/bin/bash > + > +# SYNOPSIS > +# ./100list_probes.sh > +# > +# DESCRIPTION > +# List all probes. There are many. > + > +sudo /usr/sbin/dtrace -l | head -10 > +echo "[...]" > +sudo /usr/sbin/dtrace -l | tail -10 > diff --git a/examples/language_features/101count_probes_by_provider.sh b/examples/language_features/101count_probes_by_provider.sh > new file mode 100755 > index 000000000..e897a1062 > --- /dev/null > +++ b/examples/language_features/101count_probes_by_provider.sh > @@ -0,0 +1,12 @@ > +#!/bin/bash > + > +# SYNOPSIS > +# ./101count_probes_by_provider.sh > +# > +# DESCRIPTION > +# The second column lists probes' providers. Count how > +# many probes there are for each provider. Use "tail" to > +# start at the second line of output, since the first line > +# has the column headers, which we want to ignore. > + > +sudo /usr/sbin/dtrace -l | tail -n +2 | awk '{print $2}' | sort | uniq -c > diff --git a/examples/language_features/102list_probe_arguments.sh b/examples/language_features/102list_probe_arguments.sh > new file mode 100755 > index 000000000..3d6eff537 > --- /dev/null > +++ b/examples/language_features/102list_probe_arguments.sh > @@ -0,0 +1,11 @@ > +#!/bin/bash > + > +# SYNOPSIS > +# ./102list_probe_arguments.sh > +# > +# DESCRIPTION > +# Some providers provide typed arguments for (some of) their > +# probes. Use "dtrace -lv" for a verbose listing to see the > +# arguments and their types, if any. > + > +sudo /usr/sbin/dtrace -lv -n 'syscall::open:entry' > diff --git a/examples/language_features/110provider_profile.d b/examples/language_features/110provider_profile.d > new file mode 100755 > index 000000000..7f9e75b7d > --- /dev/null > +++ b/examples/language_features/110provider_profile.d > @@ -0,0 +1,29 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./110provider_profile.d > + * > + * DESCRIPTION > + * The profile provider has basically two kinds of probes: > + * - profile probes fire on all CPUs each time period > + * - tick probes fire only once each time period > + * One can specify either a frequency or a time period. > + */ > + > +/* > + * A profile probe is used with higher frequency to sample > + * what is executing on the system. > + */ > +profile:::profile-10hz > +{ > + printf("CPU %d: running %s\n", cpu, execname); > +} > + > +/* > + * A tick probe is used to fire once to stop data collection. > + */ > +profile:::tick-2sec > +{ > + exit(0); > +} > diff --git a/examples/language_features/120provider_proc.d b/examples/language_features/120provider_proc.d > new file mode 100755 > index 000000000..7c442f39f > --- /dev/null > +++ b/examples/language_features/120provider_proc.d > @@ -0,0 +1,37 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./120provider_proc.d > + * > + * DESCRIPTION > + * We can track when processes throughout their life cycle. > + */ > + > +proc:::create > +{ > + printf("%s %s\n", probename, args[0]->pr_fname); > +} > + > +proc:::exec > +{ > + printf("%s %s\n", probename, args[0]); > +} > + > +proc:::start > +{ > + printf("%s %s\n", probename, execname); > +} > + > +proc:::exit > +{ > + printf("%s %s\n", probename, execname); > +} > + > +/* > + * A tick probe is used to fire once to stop data collection. > + */ > +profile:::tick-10sec > +{ > + exit(0); > +} > diff --git a/examples/language_features/130provider_sched_on_off_cpu.d b/examples/language_features/130provider_sched_on_off_cpu.d > new file mode 100755 > index 000000000..0d927bc3d > --- /dev/null > +++ b/examples/language_features/130provider_sched_on_off_cpu.d > @@ -0,0 +1,28 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./130provider_sched_on_off_cpu.d > + * > + * DESCRIPTION > + * We can track when processes start and end execution > + * on a CPU. > + */ > + > +sched:::on-cpu > +{ > + printf("on CPU %d is %s\n", curcpu->cpu_id, curlwpsinfo->pr_name); > +} > + > +sched:::off-cpu > +{ > + printf("off CPU %d is %s\n", curcpu->cpu_id, args[0]->pr_name); > +} > + > +/* > + * A tick probe is used to fire once to stop data collection. > + */ > +profile:::tick-2sec > +{ > + exit(0); > +} > diff --git a/examples/language_features/131provider_sched_enqueue_dequeue.d b/examples/language_features/131provider_sched_enqueue_dequeue.d > new file mode 100755 > index 000000000..c773dc908 > --- /dev/null > +++ b/examples/language_features/131provider_sched_enqueue_dequeue.d > @@ -0,0 +1,24 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./131provider_sched_enqueue_dequeue.d > + * > + * DESCRIPTION > + * We can track when processes are enqueued and > + * dequeued on CPUs. > + */ > + > +sched:::dequeue, > +sched:::enqueue > +{ > + printf(" %s %s\n", probename, args[0]->pr_name); > +} > + > +/* > + * A tick probe is used to fire once to stop data collection. > + */ > +profile:::tick-2sec > +{ > + exit(0); > +} > diff --git a/examples/language_features/140provider_syscall.d b/examples/language_features/140provider_syscall.d > new file mode 100755 > index 000000000..370e7063d > --- /dev/null > +++ b/examples/language_features/140provider_syscall.d > @@ -0,0 +1,20 @@ > +#!/usr/sbin/dtrace -qs > + > +/* > + * SYNOPSIS > + * sudo ./140provider_syscall.d > + * > + * DESCRIPTION > + * With the syscall provider, you can probe the entry to > + * and return from any system call, which is useful for > + * watching how a program moves between user space and the > + * kernel. > + */ > + > +/* probe on entry to system call write() */ > +syscall::write:entry > +{ > + printf("write %d bytes to fd %d\n", args[2], args[0]); > + > + exit(0); > +} > diff --git a/examples/language_features/150provider_fbt.d b/examples/language_features/150provider_fbt.d > new file mode 100755 > index 000000000..6dd30e264 > --- /dev/null > +++ b/examples/language_features/150provider_fbt.d > @@ -0,0 +1,48 @@ > +#!/usr/sbin/dtrace -qs > + > +/* > + * SYNOPSIS > + * sudo ./150provider_fbt.d > + * > + * DESCRIPTION > + * Function boundary tracing (fbt) can be used to trace the > + * beginning and end of just about any function in the kernel. > + * As such, it is very powerful. > + * > + * That said, there are some challenges: > + * > + * - One must know the kernel fairly well. There may > + * be tens of thousands of functions available to trace. > + * > + * - Functions that can be traced will vary from one > + * kernel build to another. For example, a function > + * might be inlined in a kernel build, making that > + * function not traceable in that build. > + * > + * Also, there are both: > + * > + * - an fbt provider, which supports typed probe arguments > + * (seen with "dtrace -lvP fbt") > + * > + * - a rawfbt provider, whose probe arguments are not typed > + * nor specially ordered; traceable functions include > + * compiler-generated optimized variants of functions, > + * named <func>.<suffix>. > + */ > + > +/* probe on entry to kernel function ksys_write() */ > +fbt::ksys_write:entry > +{ > + printf("write %d bytes to fd %d\n", args[2], args[0]); > +} > + > +/* do the same thing with a rawfbt probe, so the args are not typed */ > +rawfbt::ksys_write:entry > +{ > + printf("write %d bytes to fd %d\n", arg2, arg0); > +} > + > +fbt::ksys_write:return > +{ > + exit(0); > +} > diff --git a/examples/language_features/160provider_sdt_rawtp.sh b/examples/language_features/160provider_sdt_rawtp.sh > new file mode 100755 > index 000000000..92ac621eb > --- /dev/null > +++ b/examples/language_features/160provider_sdt_rawtp.sh > @@ -0,0 +1,36 @@ > +#!/bin/bash > + > +# SYNOPSIS > +# ./160provider_sdt_rawtp.sh > +# > +# DESCRIPTION > +# Statically Defined Tracing (SDT) refers to probes placed > +# in the kernel source code by kernel developers to support > +# tracing in stable, semantically meaningful terms. In the > +# case of Linux, this means tracepoints. > + > +# You can see these tracepoints via the sdt provider. > +sudo /usr/sbin/dtrace -lP sdt > + > +# You can see the exact same probes via the rawtp provider. > +sudo /usr/sbin/dtrace -lP rawtp > + > +# The difference is that the rawtp provider gives DTrace users > +# access to the raw tracepoints exposed by the kernel tracing > +# system, including access to the untranslated arguments of the > +# associated tracepoint events. Regular tracepoints often expose > +# translated arguments based on the raw arguments that were passed > +# in the tracepoint call. > + > +# For example, the DTrace sched provider implements the "off-cpu" > +# probe by using "rawtp:sched::sched_switch" and the "wakeup" probe > +# by using "rawtp:sched::sched_wakeup". We can see how the typed > +# arguments for these probes depend on whether we are using the > +# sdt or the rawtp provider: > + > +sudo /usr/sbin/dtrace -lvn :sched::sched_switch | grep args > +sudo /usr/sbin/dtrace -lvn :sched::sched_wakeup | grep args > + > +# Here, the module "sched" is named, but the provider name, > +# expected before the first colon ":", is left blank as a > +# wildcard to pick up both providers with these probes. > diff --git a/examples/language_features/170provider_lockstat.sh b/examples/language_features/170provider_lockstat.sh > new file mode 100755 > index 000000000..de7913a82 > --- /dev/null > +++ b/examples/language_features/170provider_lockstat.sh > @@ -0,0 +1,17 @@ > +#!/bin/bash > + > +# SYNOPSIS > +# ./170provider_lockstat.sh > +# > +# DESCRIPTION > +# The lockstat provider can be used to study lock usage. > +# For example, here we count how many times spin locks > +# and adaptive locks are acquired by the command "date". > + > +sudo /usr/sbin/dtrace -qn ' > +lockstat:::spin-acquire, > +lockstat:::adaptive-acquire > +/pid == $target/ > +{ > + @locks[probename] = count(); > +}' -c date > diff --git a/examples/language_features/171provider_io.d b/examples/language_features/171provider_io.d > new file mode 100755 > index 000000000..b91ba6cf5 > --- /dev/null > +++ b/examples/language_features/171provider_io.d > @@ -0,0 +1,31 @@ > +#!/usr/sbin/dtrace -qs > + > +/* > + * SYNOPSIS > + * sudo ./171provider_io.d > + * > + * DESCRIPTION > + * The io provider can be used to study I/O operations. > + * For example, here we print whenever an I/O operation > + * is started over the course of ten seconds, reporting > + * the device name and whether it is a read or write > + * operation. Consult the documentation for more > + * information on the probes and their arguments. > + */ > + > +BEGIN > +{ > + printf("%10s %2s\n", "DEVICE", "RW"); > +} > + > +io:::start > +{ > + printf("%10s %2s\n", > + args[1]->dev_statname, > + args[0]->b_flags & B_READ ? "R" : "W"); > +} > + > +tick-10s > +{ > + exit(0); > +} > diff --git a/examples/language_features/172provider_ip.d b/examples/language_features/172provider_ip.d > new file mode 100755 > index 000000000..dce852fbd > --- /dev/null > +++ b/examples/language_features/172provider_ip.d > @@ -0,0 +1,26 @@ > +#!/usr/sbin/dtrace -qs > + > +/* > + * SYNOPSIS > + * sudo ./172provider_ip.d > + * > + * DESCRIPTION > + * The ip provider can be used to study IP communications. > + * Here is an example that tracks sends and receives, > + * reporting their source and destination addresses for > + * 10 seconds. > + * > + * Consult the documentation for further information about > + * ip probe arguments. > + */ > + > +ip:::send, > +ip:::receive > +{ > + printf("%s: from %s to %s\n", probename, args[2]->ip_saddr, args[2]->ip_daddr); > +} > + > +tick-10s > +{ > + exit(0); > +} > diff --git a/examples/language_features/180provider_cpc.d b/examples/language_features/180provider_cpc.d > new file mode 100755 > index 000000000..a2ce8b271 > --- /dev/null > +++ b/examples/language_features/180provider_cpc.d > @@ -0,0 +1,52 @@ > +#!/usr/sbin/dtrace -qs > + > +/* > + * SYNOPSIS > + * sudo ./180provider_cpc.d > + * > + * DESCRIPTION > + * The cpc (CPU Performance Counter) provider can be used > + * profile activity based on hardware performance counters. > + * > + * For a list of cpc probes, use "dtrace -lP cpc". > + * > + * Probe specifications are of the form: > + * > + * cpc:::<event name>-<mode>-<count> > + * > + * The "event name" tells you which counters are available > + * on your hardware. > + * > + * The "mode" can be "kernel", "user", or "all", even if > + * only "all" is listed. > + * > + * The "count" indicates how many times the event is seen > + * before the probe fires. If the listed "count" is not > + * suitable for your purposes, you can specify a different > + * value. It is usually best to start with a higher value, > + * decreasing it if there are not enough probe firings, > + * rather than starting too low and inundating your system > + * with very many probe firings. > + * > + * Here, an event perf_count_sw_cpu_clock-all-1000000000 > + * was listed by "dtrace -lP cpc". We tweak the "mode" > + * and "count" for our purposes. The probe will fire every > + * 300 usecs of kernel activity. We use aggregations to > + * count how many times each call stack is seen. The > + * aggregation will be printed by default when the D > + * script exits, after 10 seconds. > + * > + * Consult the documentation for further information about > + * cpc probes. > + */ > + > +cpc:::perf_count_sw_cpu_clock-kernel-300000000 > +{ > + @[stack()] = count(); > +} > + > +/* run for only 10 seconds */ > +tick-10s > +{ > + exit(0); > +} > diff --git a/examples/language_features/200built-in-variables-probe.d b/examples/language_features/200built-in-variables-probe.d > new file mode 100755 > index 000000000..5d7e97260 > --- /dev/null > +++ b/examples/language_features/200built-in-variables-probe.d > @@ -0,0 +1,18 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./200built-in-variables-probe.d > + * > + * DESCRIPTION > + * We can get a probe's name components when it fires. > + * The fully qualified name is provider:module:function:name, > + * which we get with the built-in variables probeprov, > + * probemod, probefunc, and probename, respectively. > + */ > + > +syscall:::entry > +{ > + printf("%s:%s:%s:%s\n", probeprov, probemod, probefunc, probename); > + exit(0); > +} > diff --git a/examples/language_features/201built-in-variables-timestamps.d b/examples/language_features/201built-in-variables-timestamps.d > new file mode 100755 > index 000000000..c07ee0456 > --- /dev/null > +++ b/examples/language_features/201built-in-variables-timestamps.d > @@ -0,0 +1,31 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./201built-in-variables-timestamps.d > + * > + * DESCRIPTION > + * Built-in variables provide timestamps: > + * > + * - timestamp counts nanoseconds since > + * some arbitrary point in the past. > + * Use differences between values to measure > + * elapsed time. The value is captured only > + * once per clause. > + * > + * - walltimestamp counts nanoseconds since > + * 00:00 Universal Coordinated Time, January 1, 1970. > + */ > + > +dtrace:::BEGIN > +{ > + printf("\n%d %d\n", timestamp, walltimestamp); > + printf( "%d %d\n", timestamp, walltimestamp); > +} > + > +dtrace:::BEGIN > +{ > + printf("\n%d %d\n", timestamp, walltimestamp); > + printf( "%d %d\n", timestamp, walltimestamp); > + exit(0); > +} > diff --git a/examples/language_features/202built-in-variables-args.d b/examples/language_features/202built-in-variables-args.d > new file mode 100755 > index 000000000..192fff8e1 > --- /dev/null > +++ b/examples/language_features/202built-in-variables-args.d > @@ -0,0 +1,28 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./202built-in-variables-args.d > + * > + * DESCRIPTION > + * A probe's arguments can be accessed through the built-in > + * variables arg0, arg1, arg2, etc. These are all signed, > + * 64-bit integers, whose meanings depend on the probe. > + * > + * Some probes have typed arguments args[0], args[1], args[2], > + * etc. To see the types, use "dtrace -lvn $probe". Their > + * meanings are described in the documentation. > + * > + * When arguments are typed, they may also be reordered. > + * So there may be no correspondence between, say, arg0 > + * and args[0]. > + * > + * Typically, it is better to use the typed args[] when > + * the probe has them. > + */ > + > +syscall::write:entry > +{ > + printf("Write %d bytes to fd %d\n", args[2], arg0); > + exit(0); > +} > diff --git a/examples/language_features/203built-in-variables-process-info.d b/examples/language_features/203built-in-variables-process-info.d > new file mode 100755 > index 000000000..82600ba9e > --- /dev/null > +++ b/examples/language_features/203built-in-variables-process-info.d > @@ -0,0 +1,31 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./203built-in-variables-process-info.d > + * > + * DESCRIPTION > + * A number of built-in variables describe the process > + * that is running. > + */ > + > +syscall::write:entry > +{ > + printf("\n\n"); > + printf("The CPU is %d (%d).\n", curcpu->cpu_id, cpu); > + > + printf("\n"); > + printf("The exec name can be accessed through\n"); > + printf(" the struct task_struct: %s\n", curthread->comm); > + printf(" or a built-in variable: %s\n", execname); > + > + printf("\n"); > + printf("The execargs are: %s\n", execargs); > + > + printf("\n"); > + printf("The group id and user id are %d and %d.\n", gid, uid); > + printf("The process id and thread id are %d and %d.\n", pid, tid); > + printf("The parent process id is %d.\n\n", ppid); > + > + exit(0); > +} > diff --git a/examples/language_features/204built-in-variables-uregs.d b/examples/language_features/204built-in-variables-uregs.d > new file mode 100755 > index 000000000..55e333218 > --- /dev/null > +++ b/examples/language_features/204built-in-variables-uregs.d > @@ -0,0 +1,31 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./204built-in-variables-uregs.d > + * > + * DESCRIPTION > + * The uregs[] array can be used to access the current thread's > + * saved user-mode register values at probe firing time. The > + * available registers depend on the chip architecture: > + * > + * - x86_64 > + * R_SP R_PC R_FP R_TRAPNO R_ERR > + * R_CS R_DS R_ES R_FS R_GS R_PS R_SS > + * R_RSP R_EBP R_RFL R_RIP R_RDI R_RSI R_RAX R_RBX R_RCX R_RDX > + * R_ESP R_RBP R_EFL R_EIP R_EDI R_ESI R_EAX R_EBX R_ECX R_EDX > + * R_R0 R_R1 R_R8 R_R9 R_R10 R_R11 R_R12 R_R13 R_R14 R_R15 > + * > + * - aarch64: > + * R_SP R_PC R_PSTATE R_FP > + * R_X0 R_X1 R_X2 R_X3 R_X4 R_X5 R_X6 R_X7 R_X8 R_X9 > + * R_X10 R_X11 R_X12 R_X13 R_X14 R_X15 R_X16 R_X17 R_X18 R_X19 > + * R_X20 R_X21 R_X22 R_X23 R_X24 R_X25 R_X26 R_X27 R_X28 R_X29 > + * R_X30 > + */ > + > +BEGIN > +{ > + printf("0x%x 0x%x\n", uregs[R_PC], uregs[R_SP]); > + exit(0); > +} > diff --git a/examples/language_features/300actions-exit.sh b/examples/language_features/300actions-exit.sh > new file mode 100755 > index 000000000..fea6cb50d > --- /dev/null > +++ b/examples/language_features/300actions-exit.sh > @@ -0,0 +1,18 @@ > +#!/bin/bash > + > +# SYNOPSIS > +# sudo ./300actions-exit.sh > +# > +# DESCRIPTION > +# The exit() action terminates the script, returning an > +# unsigned 8-bit integer value. > + > +/usr/sbin/dtrace -n ' > +BEGIN > +{ > + x = 123; > + y = 456; > + exit(x < y ? x : y); > +}' > + > +echo $? > diff --git a/examples/language_features/301actions-print.d b/examples/language_features/301actions-print.d > new file mode 100755 > index 000000000..0b3742644 > --- /dev/null > +++ b/examples/language_features/301actions-print.d > @@ -0,0 +1,32 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./301actions-print.d > + * > + * DESCRIPTION > + * There are multiple ways to examine data values. > + */ > + > +BEGIN > +{ > + /* printf() is a C-like formatted print */ > + /* note: %d can be used with any size of integer */ > + printf("%c %d %s\n", 'a', 1234ll, "hello"); > + > + /* trace() uses data-type information to format */ > + trace('a'); > + trace(1234); > + trace("hello"); > + > + /* tracemem() dumps a specified number of bytes */ > + tracemem(`linux_banner, 64); > + > + /* > + * print() uses data-type information to print and annotate > + * contents at a pointer > + */ > + print(curthread); > + > + exit(0); > +} > diff --git a/examples/language_features/302actions-strings.d b/examples/language_features/302actions-strings.d > new file mode 100755 > index 000000000..097eff064 > --- /dev/null > +++ b/examples/language_features/302actions-strings.d > @@ -0,0 +1,45 @@ > +#!/usr/sbin/dtrace -s > + > +#pragma D option quiet > + > +/* > + * SYNOPSIS > + * sudo ./302actions-strings.d > + * > + * DESCRIPTION > + * There are functions to manipulate strings. > + */ > + > +BEGIN > +{ > + /* find the length of a string */ > + printf("length of 'abcde' is %d\n", strlen("abcde")); > + > + /* various other functions also resemble libc */ > + printf("text starts with first 'd': %s\n", strchr("abcdefedbca", 'd')); > + printf("text starts with last 'd': %s\n", strrchr("abcdefedbca", 'd')); > + printf("text starts with 'def': %s\n", strstr("abcdefedbca", "def")); > + > + /* break a string up into tokens */ > + printf("token #1: %s\n", strtok("hello world", " ")); > + printf("token #2: %s\n", strtok(NULL, " ")); > + > + /* join (concatenate) strings */ > + printf("join 'abc' and 'def': %s\n", strjoin("abc", "def")); > + > + /* dump part of a string */ > + printf("start at char #4: %s\n", substr("abcdefghij", 4)); > + > + /* dump part of a string, only 2 chars */ > + printf("start at char #4: %s\n", substr("abcdefghij", 4, 2)); > + > + /* find index of a substring */ > + printf("found at char #%d\n", index("abcdefghij", "def")); > + printf("found at char #%d\n", rindex("abcdefghij", "def")); > + printf("found at char #%d\n", index("abcdefghij", "XXXX")); > + > + /* convert an integer to a string */ > + printf("123000 + 456 = %s\n", lltostr(123000 + 456)); > + > + exit(0); > +} > diff --git a/examples/language_features/303actions-strings-paths.d b/examples/language_features/303actions-strings-paths.d > new file mode 100755 > index 000000000..9588d08f5 > --- /dev/null > +++ b/examples/language_features/303actions-strings-paths.d > @@ -0,0 +1,25 @@ > +#!/usr/sbin/dtrace -s > + > +#pragma D option quiet > + > +/* > + * SYNOPSIS > + * sudo ./303actions-strings-paths.d > + * > + * DESCRIPTION > + * There are functions to manipulate strings, specifically path names. > + */ > + > +BEGIN > +{ > + /* find the base name of a path */ > + printf("base is %s\n", basename("/usr/sbin/dtrace")); > + > + /* find the directory of a path */ > + printf("directory is %s\n", dirname("/usr/sbin/dtrace")); > + > + /* clean up a path name */ > + printf("cleaned up path is %s\n", cleanpath("////usr/bin/../sbin/././//dtrace")); > + > + exit(0); > +} > diff --git a/examples/language_features/304actions-system.d b/examples/language_features/304actions-system.d > new file mode 100755 > index 000000000..001566808 > --- /dev/null > +++ b/examples/language_features/304actions-system.d > @@ -0,0 +1,22 @@ > +#!/usr/sbin/dtrace -s > + > +#pragma D option quiet > +#pragma D option destructive > + > +/* > + * SYNOPSIS > + * sudo ./304actions-system.d > + * > + * DESCRIPTION > + * One can launch system calls from within D script, > + * but this must be explicitly allowed with the "destructive" > + * option or dtrace -w switch. > + */ > + > +BEGIN > +{ > + system("ls"); > + system("echo hello world"); > + > + exit(0); > +} > diff --git a/examples/language_features/305actions-progenyof.d b/examples/language_features/305actions-progenyof.d > new file mode 100755 > index 000000000..2aa3e8ea3 > --- /dev/null > +++ b/examples/language_features/305actions-progenyof.d > @@ -0,0 +1,20 @@ > +#!/usr/sbin/dtrace -s > + > +#pragma D option quiet > + > +/* > + * SYNOPSIS > + * sudo ./305actions-progenyof.d > + * > + * DESCRIPTION > + * One can test whether one is progeny of another process. > + */ > + > +BEGIN > +{ > + printf("I am%s progeny of pid 1234\n", progenyof(1234) ? "" : " not"); > + printf("I am%s progeny of myself\n", progenyof(pid) ? "" : " not"); > + printf("I am%s progeny of my parent\n", progenyof(ppid) ? "" : " not"); > + > + exit(0); > +} > diff --git a/examples/language_features/306actions-speculations.d b/examples/language_features/306actions-speculations.d > new file mode 100755 > index 000000000..7e0d21370 > --- /dev/null > +++ b/examples/language_features/306actions-speculations.d > @@ -0,0 +1,57 @@ > +#!/usr/sbin/dtrace -s > + > +#pragma D option quiet > + > +/* > + * SYNOPSIS > + * sudo ./306actions-speculations.d > + * > + * DESCRIPTION > + * In DTrace, one can write output speculatively, deciding at a > + * later time whether to commit or discard the speculative output. > + */ > +#pragma D option nspec=2 > + > +BEGIN > +{ > + /* create two speculations */ > + s1 = speculation(); > + s2 = speculation(); > +} > + > +BEGIN > +{ > + /* the clause has "speculate()" before data recording */ > + speculate(s1); > + printf("one\n"); > +} > + > +BEGIN > +{ > + speculate(s2); > + printf("two\n"); > +} > + > +BEGIN > +{ > + speculate(s1); > + printf("three\n"); > +} > + > +BEGIN > +{ > + speculate(s2); > + printf("four\n"); > +} > + > +BEGIN > +{ > + commit(s1); /* commit "one" "three" output */ > + discard(s2); /* discard "two" "four" output */ > +} > + > +BEGIN > +{ > + /* cannot be in same clause as commit/discard */ > + exit(0); > +} > diff --git a/examples/language_features/307actions-callstack.d b/examples/language_features/307actions-callstack.d > new file mode 100755 > index 000000000..8e3d6fe47 > --- /dev/null > +++ b/examples/language_features/307actions-callstack.d > @@ -0,0 +1,54 @@ > +#!/usr/sbin/dtrace -qs > + > +/* > + * SYNOPSIS > + * sudo ./307actions-callstack.d > + * > + * DESCRIPTION > + * In DTrace, one can get information about the call stack. > + */ > + > +/* have a probe fire somewhere in the kernel */ > +fbt::ksys_write:entry > +{ > + /* dump the kernel call stack */ > + stack(); > + > + /* a built-in variable gives the number of frames */ > + printf("%d frames\n", stackdepth); > + > + /* another built-in variable gives the caller PC */ > + printf("second frame is the caller %p\n", caller); > + > + /* we can get the symbolic name of its module */ > + printf( " module "); mod(caller); > + > + /* we can get the symbolic name of its function */ > + printf("\n function "); func(caller); > + > + /* sym() is an alias for func() */ > + printf("\n == symbol"); sym(caller); > + > + /* > + * Similarly, we can also get the user-space call stack > + * through ustack(). The related built-in variables are > + * ustackdepth and ucaller. Conversion to symbolic names > + * can be made via umod(), ufunc(), usym(), and uaddr(). > + * User-space call stacks face a few challenges: > + * > + * - The BPF helper functions rely on frame-pointer > + * chasing, which can be impaired or even incorrect > + * unless -fno-omit-frame-pointer is specified. > + * > + * - Conversion to symbolic names does not take place when > + * the probe fires but later, in user space, when results > + * are printed. It is possible that the user application > + * has already terminated and the information about its > + * address space gone. > + * > + * - For a stripped executable, you must specify > + * --export-dynamic when linking the program. > + */ > + > + exit(0); > +} > diff --git a/examples/language_features/310actions-alloca-copy.d b/examples/language_features/310actions-alloca-copy.d > new file mode 100755 > index 000000000..1a48c696b > --- /dev/null > +++ b/examples/language_features/310actions-alloca-copy.d > @@ -0,0 +1,95 @@ > +#!/usr/sbin/dtrace -qs > + > +#pragma D option strsize=32 > + > +/* > + * SYNOPSIS > + * sudo ./310actions-alloca-copy.d > + * > + * DESCRIPTION > + * A DTrace program has scratch memory that it manages > + * for its own purposes. The program can allocate scratch > + * memory as well as copy into, out of, and between buffers. > + * It is automatically freed at the end of each clause. > + */ > + > +/* alloca */ > +BEGIN > +{ > + /* alloca() a string */ > + ptr = (string *) alloca(32); > + > + /* set its contents (truncated to strsize chars, including NUL) */ > + *ptr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; > + > + /* print it */ > + trace(*ptr); > + > + /* end of the clause: ptr is freed */ > +} > + > +/* bcopy */ > +BEGIN > +{ > + /* alloca() a string */ > + ptr = (string *) alloca(32); > + > + /* copy from kernel memory to scratch memory */ > + bcopy(`linux_banner, ptr, 32); > + > + /* print it */ > + printf("\n%s", *ptr); > + > + /* end of the clause: ptr is freed */ > +} > + > +/* copyinto */ > +syscall::write:entry > +{ > + /* alloca() a string */ > + ptr = (string *) alloca(32); > + > + /* copy from user space into scratch memory */ > + copyinto(arg1, 32, ptr); > + > + /* print it */ > + printf("\n%s to fd %d, %d bytes", *ptr, arg0, arg2); > + > + /* end of the clause: ptr is freed */ > +} > + > +/* copyin */ > +syscall::write:entry > +{ > + /* copy from user space to scratch memory, allocating the pointer */ > + ptr = copyin(arg1, 32); > + > + /* print it */ > + printf("\n%s to fd %d, %d bytes", *ptr, arg0, arg2); > + > + /* end of the clause: ptr is freed */ > +} > + > +/* copyinstr */ > +syscall::write:entry > +{ > + /* copy string from user space to scratch memory, allocating the pointer */ > + str = copyinstr(arg1); > + > + /* print it */ > + printf("\n%s to fd %d, %d bytes", str, arg0, arg2); > + > + /* end of the clause: ptr is freed */ > +} > + > +/* > + * There are also copyout() and copyoutstr() functions, that may be > + * used to copy from scratch memory to user-space buffers. Since they > + * alter the behavior of the user code, the "destructive" option -w > + * must be specified. > + */ > + > +syscall::write:entry > +{ > + exit(0); > +} > diff --git a/examples/language_features/311actions-rand.d b/examples/language_features/311actions-rand.d > new file mode 100755 > index 000000000..54500fb3b > --- /dev/null > +++ b/examples/language_features/311actions-rand.d > @@ -0,0 +1,25 @@ > +#!/usr/sbin/dtrace -qs > + > +/* > + * SYNOPSIS > + * sudo ./311actions-rand.d > + * > + * DESCRIPTION > + * The rand() function generates a random integer. > + */ > + > +BEGIN > +{ > + printf(" %3d\n", rand() & 0xff); > + printf(" %3d\n", rand() & 0xff); > + printf(" %3d\n", rand() & 0xff); > + printf(" %3d\n", rand() & 0xff); > + printf(" %3d\n", rand() & 0xff); > + printf(" %3d\n", rand() & 0xff); > + printf(" %3d\n", rand() & 0xff); > + printf(" %3d\n", rand() & 0xff); > + printf(" %3d\n", rand() & 0xff); > + printf(" %3d\n", rand() & 0xff); > + > + exit(0); > +} > diff --git a/examples/language_features/500aggregations-intro.d b/examples/language_features/500aggregations-intro.d > new file mode 100755 > index 000000000..54b5cbe6b > --- /dev/null > +++ b/examples/language_features/500aggregations-intro.d > @@ -0,0 +1,24 @@ > +#!/usr/sbin/dtrace -s > + > +#pragma D option quiet > + > +/* > + * SYNOPSIS > + * sudo ./500aggregations-intro.d > + * > + * DESCRIPTION > + * Aggregations can be used to collect statistical data on > + * some value. Results are printed by default when the > + * script terminates. > + */ > + > +tick-20hz > +{ > + /* do not even bother naming the aggregation; just "@" */ > + @ = count(); > +} > + > +tick-1sec > +{ > + exit(0); > +} > diff --git a/examples/language_features/501aggregations-names-keys.d b/examples/language_features/501aggregations-names-keys.d > new file mode 100755 > index 000000000..06ede5301 > --- /dev/null > +++ b/examples/language_features/501aggregations-names-keys.d > @@ -0,0 +1,19 @@ > +#!/usr/sbin/dtrace -s > + > +/* > + * SYNOPSIS > + * sudo ./501aggregations-names-keys.d > + * > + * DESCRIPTION > + * Aggregations can be named or use keys. > + */ > + > +tick-20hz > +{ > + @my_count[(timestamp % 2 == 0) ? "even" : "odd"] = count(); > +} > + > +tick-1sec > +{ > + exit(0); > +} > diff --git a/examples/language_features/502aggregations-basic-funcs.d b/examples/language_features/502aggregations-basic-funcs.d > new file mode 100755 > index 000000000..b55a42117 > --- /dev/null > +++ b/examples/language_features/502aggregations-basic-funcs.d > @@ -0,0 +1,26 @@ > +#!/usr/sbin/dtrace -s > + > +# pragma D option quiet > + > +/* > + * SYNOPSIS > + * sudo ./501aggregations-basic-funcs.d > + * > + * DESCRIPTION > + * Aggregations can include basic statistical functions. > + */ > + > +tick-20hz > +{ > + @my_count["count"] = count(); > + @my_sum["sum"] = sum(timestamp); > + @my_avg["average"] = avg(timestamp); > + @my_stddev["standard deviation"] = stddev(timestamp); > + @my_min["minimum"] = min(timestamp); > + @my_max["maximum"] = max(timestamp); > +} > + > +tick-1sec > +{ > + exit(0); > +} > diff --git a/examples/language_features/503aggregations-stack.d b/examples/language_features/503aggregations-stack.d > new file mode 100755 > index 000000000..3e297c34b > --- /dev/null > +++ b/examples/language_features/503aggregations-stack.d > @@ -0,0 +1,24 @@ > +#!/usr/sbin/dtrace -s > + > +# pragma D option quiet > + > +/* > + * SYNOPSIS > + * sudo ./503aggregations-stack.d > + * > + * DESCRIPTION > + * An interesting key to use is "stack()", giving you > + * information, for example, about hot kernel call stacks. > + * Each distinct kernel call stack found will be reported > + * along with the number of times it was encountered. > + */ > + > +tick-20hz > +{ > + @[stack()] = count(); > +} > + > +tick-1sec > +{ > + exit(0); > +} > diff --git a/examples/language_features/504aggregations-printa.d b/examples/language_features/504aggregations-printa.d > new file mode 100755 > index 000000000..6867511e2 > --- /dev/null > +++ b/examples/language_features/504aggregations-printa.d > @@ -0,0 +1,29 @@ > +#!/usr/sbin/dtrace -s > + > +# pragma D option quiet > + > +/* > + * SYNOPSIS > + * sudo ./504aggregations-printa.d > + * > + * DESCRIPTION > + * While aggregations are printed by default when the D > + * script terminates, it can be useful to print aggregations > + * explicitly using the printa() function -- either to use > + * detailed formatting or if results should be printed > + * while the script is still running. In addition to the > + * usual formatting directives used by printf(), printa() > + * also uses "@" directives for the aggregation values. > + */ > + > +tick-20hz > +{ > + @["key"] = count(); > +} > + > +tick-1sec > +{ > + printa("KEY BEFORE VALUE: %s %@d\n", @); > + printa("VALUE BEFORE KEY: %@d %s\n", @); > + exit(0); > +} > diff --git a/examples/language_features/505aggregations-quantize.d b/examples/language_features/505aggregations-quantize.d > new file mode 100755 > index 000000000..5ae382843 > --- /dev/null > +++ b/examples/language_features/505aggregations-quantize.d > @@ -0,0 +1,65 @@ > +#!/usr/sbin/dtrace -s > + > +# pragma D option quiet > + > +/* > + * SYNOPSIS > + * sudo ./505aggregations-quantize.d > + * > + * DESCRIPTION > + * While avg(), stddev(), min(), and max() are useful for > + * characterizing the distribution of values crudely, one > + * may also be interested in more detail on a distribution. > + * > + * Aggregations can count by value after the value has been > + * "quantized" -- that is, grouped into bins. > + */ > + > +BEGIN > +{ > + /* time origin at the beginning of the script's execution */ > + t0 = timestamp; > + > + /* for this example, use some dummy value that will change in scale */ > + dummy = t0; > +} > + > +tick-20hz > +{ > + /* > + * If you have no sense for the distribution of values -- > + * not even of the scale -- then quantize(val) can be a > + * good starting point. Its only input parameter is the > + * value. Bins are powers of two -- you reduce values > + * log2() -- giving you a sense of the scale of the values. > + */ > + @crude = quantize(dummy >>= 1); > + > + /* > + * But perhaps you know the scale and want to chop some > + * range of values up linearly. So we use lquantize(). > + */ > + @linear = lquantize( > + (timestamp - t0) / 1000000, /* number of msecs since D script start */ > + 0, /* lower bound */ > + 2000, /* upper bound (msecs in 2 secs) */ > + 200); /* number per bin */ > + > + /* > + * Finally, and this is a little complicated, what if you > + * liked the original, logarithmic quantization, but you > + * just want a little more detail. Then, there is a > + * log-linear quantization. > + */ > + @log_linear = llquantize( > + dummy, /* number of msecs since some arbitrary time in the past */ > + 100, /* use log10() */ > + 3, /* lower bound is 10 to the 3 = 1000 */ > + 5, /* upper bound is 10 to the 9 = 1000000000 */ > + 4); /* number of steps per logarithmic range */ > +} > + > +tick-2sec > +{ > + exit(0); > +} > diff --git a/examples/language_features/506aggregations-clear-trunc.d b/examples/language_features/506aggregations-clear-trunc.d > new file mode 100755 > index 000000000..26314d8a8 > --- /dev/null > +++ b/examples/language_features/506aggregations-clear-trunc.d > @@ -0,0 +1,63 @@ > +#!/usr/sbin/dtrace -s > + > +# pragma D option quiet > + > +/* > + * SYNOPSIS > + * sudo ./506aggregations-clear-trunc.d > + * > + * DESCRIPTION > + * Here, we show clear() and trunc(), used with aggregations. > + * > + * One reason to use printa() is to get aggregation values > + * periodically while the D script is executing. In that > + * case, however, you may want to reset the aggregations. > + * There are two ways of doing so. > + */ > + > +tick-20hz > +{ > + /* in this example, consider two aggregations */ > + > + /* > + * "parity" counts whether the timestamp is even or odd. > + * In each one-second time interval, both cases should > + * get some values. > + */ > + @parity[(timestamp & 1) ? "odd" : "even"] = count(); > + > + /* > + * "low_bits" counts how often the low bits (0-255) appear. > + * It is reasonable that some keys will not reappear. > + */ > + @low_bits[timestamp & 0xff] = count(); > +} > + > +tick-1sec > +{ > + /* > + * Every second, we print the values for the recent > + * one-second interval. > + */ > + printa("parity: %-4s %@2d\n", @parity); > + printa("low bits: %3d %@d\n", @low_bits); > + > + /* > + * We clear out the "parity" values, leaving the keys, > + * since almost surely those keys will recur. And if > + * a key ends up with no counts, we want to know about it! > + */ > + clear(@parity); > + > + /* > + * We trunc() (truncate) "low_bits", however, since keys > + * might not reoccur. Unused keys take up memory and > + * pollute the periodic output. > + */ > + trunc(@low_bits); > +} > + > +tick-4sec > +{ > + exit(0); > +} > diff --git a/examples/language_features/507aggregations-trunc5.d b/examples/language_features/507aggregations-trunc5.d > new file mode 100755 > index 000000000..ca5fdae02 > --- /dev/null > +++ b/examples/language_features/507aggregations-trunc5.d > @@ -0,0 +1,50 @@ > +#!/usr/sbin/dtrace -s > + > +# pragma D option quiet > + > +/* > + * SYNOPSIS > + * sudo ./507aggregations-trunc5.d > + * > + * DESCRIPTION > + * Here, is another use of trunc() -- with an additional > + * argument to focus attention on the top values. > + */ > + > +BEGIN > +{ > + /* > + * The mask will change size. When it is wide, it will > + * spread values over many keys. When it is narrow, it > + * will concentrate values over a few keys. So, some > + * keys will get many values, while others will get few. > + */ > + mask = 255; > +} > + > +tick-100hz > +{ > + /* the aggregation */ > + @[timestamp & mask] = count(); > + > + /* update the mask */ > + mask >>= 1; > + mask = (mask == 0) ? 255 : mask; > +} > + > +tick-1sec > +{ > + printf("entire result\n"); > + printa(" %3d %@3d\n", @); > + > + trunc(@, 5); > + > + printf("top 5 keys\n"); > + printa(" %3d %@3d\n", @); > + > + /* > + * On exit, we will no longer print the aggregation > + * by default, since it was just printed. > + */ > + exit(0); > +} > diff --git a/examples/language_features/508aggregations-normalize.d b/examples/language_features/508aggregations-normalize.d > new file mode 100755 > index 000000000..5c2429f74 > --- /dev/null > +++ b/examples/language_features/508aggregations-normalize.d > @@ -0,0 +1,49 @@ > +#!/usr/sbin/dtrace -s > + > +# pragma D option quiet > + > +/* > + * SYNOPSIS > + * sudo ./508aggregations-normalize.d > + * > + * DESCRIPTION > + * Here, is another use of trunc() -- with an additional > + * argument to focus attention on the top values. > + */ > + > +BEGIN > +{ > + treport = timestamp; > + ttick = timestamp; > +} > + > +/* add the number of nanoseconds since the last tick */ > +tick-100hz > +{ > + @ = sum(timestamp - ttick); > + ttick = timestamp; > +} > + > +/* report at erratic intervals */ > +tick-3100ms, > +tick-3600ms > +{ > + /* determine number of usecs since last report */ > + this->us_since_last = (timestamp - treport) / 1000; > + treport = timestamp; > + printf("%8d usecs since the last report\n", this->us_since_last); > + > + /* normalize the total number of nsecs by the number of usecs */ > + normalize(@, this->us_since_last); > + > + /* report aggregation (do not worry about formatting) */ > + printa(@); > + > + /* clear the aggregation before resuming */ > + clear(@); > +} > + > +tick-12sec > +{ > + exit(0); > +} > -- > 2.47.3 > >