<chapter id="chp-xlate"><title>Translators</title><highlights><para>In <olink targetptr="chp-stab" remap="internal">Chapter&nbsp;39, Stability</olink>, we learned about how DTrace computes and reports program stability attributes. Ideally, we would like to construct our DTrace programs by consuming only Stable or Evolving interfaces. Unfortunately, when debugging a low-level problem or measuring system performance, you may need to enable probes that are associated with internal operating system routines such as functions in the kernel, rather than probes associated with more stable interfaces such as system calls. The data available at probe locations deep within the software stack is often a collection of implementation artifacts rather than more stable data structures such as those associated with the Solaris system call interfaces. In order to aid you in writing stable D programs, DTrace provides a facility to translate implementation artifacts into stable data structures accessible from your D program statements.</para>
</highlights><sect1 id="chp-xlate-1"><title>Translator Declarations</title><para>A <firstterm>translator</firstterm> is a collection of D assignment statements provided by the supplier of an interface that can be used to translate an input expression into an object of struct type. To understand the need for and use of translators, we'll consider as an example the ANSI-C standard library routines defined in <filename>stdio.h</filename>. These routines operate on a data structure named <literal>FILE</literal> whose implementation artifacts are abstracted away from C programmers. A standard technique for creating a data structure abstraction is to provide only a forward declaration of a data structure in public header files, while keeping the corresponding struct definition in a separate private header file.</para><para>If you are writing a C program and wish to know the file descriptor corresponding to a <literal>FILE</literal> struct, you can use the <olink targetdoc="refman3a" targetptr="fileno-3c" remap="external"><citerefentry><refentrytitle>fileno</refentrytitle><manvolnum>3C</manvolnum></citerefentry></olink> function to obtain the descriptor rather than dereferencing a member of the FILE struct directly. The Solaris header files enforce this rule by defining FILE as an opaque forward declaration tag so it cannot be dereferenced directly by C programs that include <literal>&lt;stdio.h&gt;</literal>. Inside the <filename>libc.so.1</filename> library, you can imagine that <function>fileno</function> is implemented in C something like this:</para><programlisting>int
fileno(FILE *fp)
{
	struct file_impl *ip = (struct file_impl *)fp;

	return (ip-&gt;fd);
}</programlisting><para>Our hypothetical <function>fileno</function> takes a <literal>FILE</literal> pointer as an argument and casts it to a pointer to a corresponding internal <filename>libc</filename> structure, <literal>struct file_impl</literal>, and then returns the value of the <literal>fd</literal> member of the implementation structure. Why does Solaris implement interfaces like this? By abstracting the details of the current <filename>libc</filename> implementation away from client programs, Sun is able to maintain a commitment to strong binary compatibility while continuing to evolve and change the internal implementation details of <filename>libc</filename>. In our example, the <literal>fd</literal> member could change size or position within <literal>struct file_impl</literal>, even in a patch, and existing binaries calling <olink targetdoc="refman3a" targetptr="fileno-3c" remap="external"><citerefentry><refentrytitle>fileno</refentrytitle><manvolnum>3C</manvolnum></citerefentry></olink> would not be affected by this change because they do not depend on these artifacts.</para><para>Unfortunately, observability software such as DTrace has the need to peer inside the implementation in order to provide useful results, and does not have the luxury of calling arbitrary C functions defined in Solaris libraries or in the kernel. You could declare a copy of <literal>struct file_impl</literal> in your D program in order to instrument the routines declared in <filename>stdio.h</filename>, but then your D program would rely on Private implementation artifacts of the library that might break in a future micro or minor release, or even in a patch. Ideally, we want to provide a construct for use in D programs that is bound to the implementation of the library and is updated accordingly, but still provides an additional layer of abstraction associated with greater stability.</para><para>A new translator is created using a declaration of the form:</para><programlisting>translator <replaceable>output-type</replaceable> &lt; <replaceable>input-type</replaceable> <replaceable>input-identifier</replaceable> &gt; {
	<replaceable>member-name</replaceable> = <replaceable>expression</replaceable> ;
	<replaceable>member-name</replaceable> = <replaceable>expression</replaceable> ;
	...
};	</programlisting><para>The <replaceable>output-type</replaceable> names a struct that will be the result type for the translation. The <replaceable>input-type</replaceable> specifies the type of the input expression, and is surrounded in angle brackets <literal>&lt; &gt;</literal> and followed by an <replaceable>input-identifier</replaceable> that can be used in the translator expressions as an alias for the input expression. The body of the translator is surrounded in braces <literal>{ }</literal> and terminated with a semicolon (<literal>;</literal>), and consists of a list of <replaceable>member-name</replaceable> and identifiers corresponding translation expressions. Each member declaration must name a unique member of the <replaceable>output-type</replaceable> and must be assigned an expression of a type compatible with the member type, according to the rules for the D assignment (<literal>=</literal>) operator.</para><para>For example, we could define a struct of stable information about <filename>stdio</filename> files based on some of the available <filename>libc</filename> interfaces:</para><programlisting>struct file_info {
	int file_fd;   /* file descriptor from fileno(3C) */
	int file_eof;  /* eof flag from feof(3C) */
};</programlisting><para>A hypothetical D translator from <literal>FILE</literal> to <literal>file_info</literal> could then be declared in D as follows:</para><programlisting>translator struct file_info &lt; FILE *F &gt; {
	file_fd = ((struct file_impl *)F)-&gt;fd;
	file_eof = ((struct file_impl *)F)-&gt;eof;
};</programlisting><para>In our hypothetical translator, the input expression is of type <literal>FILE *</literal> and is assigned the <replaceable>input-identifier</replaceable> <literal>F</literal>. The identifier <literal>F</literal> can then be used in the translator member expressions as a variable of type <literal>FILE *</literal> that is only visible within the body of the translator declaration. To determine the value of the output <literal>file_fd</literal> member, the translator performs a cast and dereference similar to the hypothetical implementation of <olink targetdoc="refman3a" targetptr="fileno-3c" remap="external"><citerefentry><refentrytitle>fileno</refentrytitle><manvolnum>3C</manvolnum></citerefentry></olink> shown above. A similar translation is performed to obtain the value of the <acronym>EOF</acronym> indicator.</para><para>Sun provides a set of translators for use with Solaris interfaces that you can invoke from your D programs, and promises to maintain these translators according to the rules for interface stability defined earlier as the implementation of the corresponding interface changes. We'll learn about these translators later in the chapter, after we learn how to invoke translators from D. The translator facility itself is also provided for use by application and library developers who wish to offer their own translators that D programmers can use to observe the state of their software packages.</para>
</sect1><sect1 id="chp-xlate-2"><title>Translate Operator</title><para>The D operator <literal>xlate</literal> is used to perform a translation from an input expression to one of the defined translation output structures. The <literal>xlate</literal> operator is used in an expression of the form:</para><programlisting>xlate &lt; <replaceable>output-type</replaceable> &gt; ( <replaceable>input-expression</replaceable> )</programlisting><para>For example, to invoke the hypothetical translator for FILE structs defined above and access the <literal>file_fd</literal> member, you would write the expression:</para><programlisting>xlate &lt;struct file_info *&gt;(f)-&gt;file_fd;</programlisting><para>where <literal>f</literal> is a D variable of type <literal>FILE *</literal>. The <literal>xlate</literal> expression itself is assigned the type defined by the <replaceable>output-type</replaceable>. Once a translator is defined, it can be used to translate input expressions to either the translator output struct type, or to a pointer to that struct.</para><para>If you translate an input expression to a struct, you can either dereference a particular member of the output immediately using the &ldquo;<literal>.</literal>&rdquo; operator, or you can assign the entire translated struct to another D variable to make a copy of the values of all the members. If you dereference a single member, the D compiler will only generate code corresponding to the expression for that member. You may not apply the <literal>&amp;</literal> operator to a translated struct to obtain its address, as the data object itself does not exist until it is copied or one of its members is referenced.</para><para>If you translate an input expression to a pointer to a struct, you can either dereference a particular member of the output immediately using the <literal>-&gt;</literal> operator, or you can dereference the pointer using the unary <literal>*</literal> operator, in which case the result behaves as if you translated the expression to a struct. If you dereference a single member, the D compiler will only generate code corresponding to the expression for that member. You may not assign a translated pointer to another D variable as the data object itself does not exist until it is copied or one of its members is referenced, and therefore cannot be addressed.</para><para>A translator declaration may omit expressions for one or more members of the output type. If an <literal>xlate</literal> expression is used to access a member for which no translation expression is defined, the D compiler will produce an appropriate error message and abort the program compilation. If the entire output type is copied by means of a structure assignment, any members for which no translation expressions are defined will be filled with zeroes.</para><para>In order to find a matching translator for an <literal>xlate</literal> operation, the D compiler examines the set of available translators in the following order:</para><itemizedlist><listitem><para>First, the compiler looks for a translation from the exact input expression type to the exact output type.</para>
</listitem><listitem><para>Second, the compiler <firstterm>resolves</firstterm> the input and output types by following any typedef aliases to the underlying type names, and then looks for a translation from the resolved input type to the resolved output type.</para>
</listitem><listitem><para>Third, the compiler looks for a translation from a compatible input type to the resolved output type. The compiler uses the same rules as it does for determining compatibility of function call arguments with function prototypes in order to determine if an input expression type is compatible with a translator's input type.</para>
</listitem>
</itemizedlist><para>If no matching translator can be found according to these rules, the D compiler produces an appropriate error message and program compilation fails.</para>
</sect1><sect1 id="chp-xlate-3"><title>Process Model Translators</title><para>The DTrace library file <filename>/usr/lib/dtrace/procfs.d</filename> provides a set of translators for use in your D programs to translate from the operating system kernel implementation structures for processes and threads to the stable <olink targetdoc="refman4" targetptr="proc-4" remap="external"><citerefentry><refentrytitle>proc</refentrytitle><manvolnum>4</manvolnum></citerefentry></olink> structures <literal>psinfo</literal> and <literal>lwpsinfo</literal>. These structures are also used in the Solaris <filename>/proc</filename> filesystem files <literal>/proc/</literal><replaceable>pid</replaceable><literal>/psinfo</literal> and <literal>/proc/</literal><replaceable>pid</replaceable><literal>/lwps/</literal><replaceable>lwpid</replaceable><literal>/lwpsinfo</literal>, and are defined in the system header file <literal>/usr/include/sys/procfs.h</literal>. These structures define useful Stable information about processes and threads such as the process ID, LWP ID, initial arguments, and other data displayed by the <olink targetdoc="refman1" targetptr="ps-1" remap="external"><citerefentry><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry></olink> command. Refer to <olink targetdoc="refman4" targetptr="proc-4" remap="external"><citerefentry><refentrytitle>proc</refentrytitle><manvolnum>4</manvolnum></citerefentry></olink> for a complete description of the struct members and semantics.</para><table frame="topbot" id="tbl-proc-xlate"><title><filename>procfs.d</filename> Translators</title><tgroup cols="4" colsep="0" rowsep="0"><colspec colwidth="1.00in"/><colspec colwidth="1.50in"/><colspec colwidth="1.00in"/><colspec colwidth="1.50in"/><thead><row rowsep="1"><entry><para>Input Type</para>
</entry><entry><para>Input Type Attributes</para>
</entry><entry><para>Output Type</para>
</entry><entry><para>Output Type Attributes</para>
</entry>
</row>
</thead><tbody><row><entry><para><literal>proc_t *</literal></para>
</entry><entry><para>Private/Private/Common</para>
</entry><entry><para><literal>psinfo_t *</literal></para>
</entry><entry><para>Stable/Stable/Common</para>
</entry>
</row><row><entry><para><literal>kthread_t *</literal></para>
</entry><entry><para>Private/Private/Common</para>
</entry><entry><para><literal>lwpsinfo_t *</literal></para>
</entry><entry><para>Stable/Stable/Common</para>
</entry>
</row>
</tbody>
</tgroup>
</table>
</sect1><sect1 id="chp-xlate-4"><title>Stable Translations</title><para>While a translator provides the ability to convert information into a stable data structure, it does not necessarily resolve all stability issues that can arise in translating data. For example, if the input expression for an xlate operation itself references Unstable data, the resulting D program is also Unstable because program stability is always computed as the minimum stability of the accumulated D program statements and expressions. Therefore, it is sometimes necessary to define a specific stable input expression for a translator in order to permit stable programs to be constructed. The D inline mechanism can be used to facilitate such <firstterm>stable translations</firstterm>.</para><para>The DTrace <filename>procfs.d</filename> library provides the <literal>curlwpsinfo</literal> and <literal>curpsinfo</literal> variables described earlier as stable translations. For example, the <literal>curlwpsinfo</literal> variable is actually an <literal>inline</literal> declared as follows:</para><programlisting>inline lwpsinfo_t *curlwpsinfo = xlate &lt;lwpsinfo_t *&gt; (curthread);
#pragma D attributes Stable/Stable/Common curlwpsinfo</programlisting><para>The <literal>curlwpsinfo</literal> variable is defined as an inlined translation from the <literal>curthread</literal> variable, a pointer to the kernel's Private data structure representing a thread, to the Stable <literal>lwpsinfo_t</literal> type. The D compiler processes this library file and caches the <literal>inline</literal> declaration, making <literal>curlwpsinfo</literal> appear as any other D variable. The <literal>#pragma</literal> statement following the declaration is used to explicitly reset the attributes of the <literal>curlwpsinfo</literal> identifier to Stable/Stable/Common, masking the reference to <literal>curthread</literal> in the inlined expression. This combination of D features permits D programmers to use curthread as the source of a translation in a safe fashion that can be updated by Sun coincident to corresponding changes in the Solaris implementation.</para>
</sect1>
</chapter>