Hi, The last months I have been trying to come up with a new way to do the debugging of the libsldap library used for native LDAP support in Solaris. Currently most debugging is done using syslog on the LOG_DEBUG level and this means that debugging is always on. After a discussion on the SPARKS mailinglist we came to the conclusion that a dtrace provider would give us a much better way to debug the library. So I started a prototype on how this provider could look like. I started the easy way by creating a dprintf dtrace probe which outputs a string and is a one on one replacement of the syslog calls currently used in the code. But from the start I wanted to be somewhat more daring is creating something like a real dtrace provider exposing some more of the internal structures used in the library allowing people to write dtrace code to debug things without lots of debugging hooks in the code. As dtrace is new to me I might not be doing the smartest moves in trying to accomplish a dtrace provider. That''s also one of the reasons to ask a question on this mailinglist as I''m somewhat stuck on how I could get this to work. The structure I''m currently am trying to export is this (I''m using a translator as I don''t want to export everything already (some structures are way complex and might be added in the future but for a prototype are now out of scope). The top structure is the Connection structure which holds the cache of LDAP connections. It is defined like this in the code. typedef int ConnectionID; /* * This structure is used by ns_connect to create and manage * one or more ldap connections within the library. */ typedef struct connection { ConnectionID connectionId; boolean_t usedBit; /* true if only used by */ /* one thread and not shared */ /* by other threads */ boolean_t notAvail; /* not sharable, delete */ /* when shared == 0 */ int shared; /* number of threads */ /* using this connection */ pid_t pid; /* process id */ char *serverAddr; ns_cred_t *auth; LDAP *ld; thread_t threadID; /* thread ID using it */ struct ns_ldap_cookie *cookieInfo; char **controls; /* from server_info */ char **saslMechanisms; /* from server_info */ } Connection; As this is an internal structure not defined in any global header files I have added the following in my libsldap.d provider /* * This is a D representation of some internal structures defined in ns_internal.h */ typedef int ConnectionID; /* * Connection structure used in most of the libsldap code. This is only a dummy. * entry as we specify both a 32 and 64 bits version of the structure for alignment purposes. */ typedef struct connection Connection; /* * 32 bit representation of the structure */ typedef struct connection32 { uint32_t connectionId; uint32_t usedBit; uint32_t notAvail; uint32_t shared; uint32_t pid; uint32_t serverAddr; uint32_t auth; uint32_t ld; uint32_t threadID; uint32_t cookieInfo; uint32_t controls; uint32_t saslMechanisms; } connection32_t; /* * 64 bit representation of the structure */ typedef struct connection64 { uint64_t connectionId; uint64_t usedBit; uint64_t notAvail; uint64_t shared; uint64_t pid; uint64_t serverAddr; uint64_t auth; uint64_t ld; uint64_t threadID; uint64_t cookieInfo; uint64_t controls; uint64_t saslMechanisms; } connection64_t; /* * For a stable interface we translate the most important stuff into a dtrace * representation of the structure. */ typedef struct libsldap_connection { int connectionId; boolean_t usedBit; /* true if only used by */ /* one thread and not shared */ /* by other threads */ boolean_t notAvail; /* not sharable, delete */ /* when shared == 0 */ int shared; /* number of threads */ /* using this connection */ pid_t pid; /* process id */ string serverAddr; uintptr_t auth; thread_t threadID; /* thread ID using it */ } libsldap_connection_t; And a translator to convert from the external definition to a dtrace structure (based on the ISCSI provider which was a good startingpoint) /* * Translator from ns_internal.h struct Connection to dtrace defined struct libsldap_connection */ #pragma D binding "1.5" translator translator struct libsldap_connection <struct connection *P> { connectionId = (curthread->t_procp->p_model == 0x00100000) ? *(uint32_t *)copyin((uintptr_t) &((connection32_t *)P)->connectionId, sizeof (uint32_t)) : *(uint64_t *)copyin((uintptr_t) &((connection64_t *)P)->connectionId, sizeof (uint64_t)); usedBit = (curthread->t_procp->p_model == 0x00100000) ? *(uint32_t *)copyin((uintptr_t) &((connection32_t *)P)->usedBit, sizeof (uint32_t)) : *(uint64_t *)copyin((uintptr_t) &((connection64_t *)P)->usedBit, sizeof (uint64_t)); notAvail = (curthread->t_procp->p_model == 0x00100000) ? *(uint32_t *)copyin((uintptr_t) &((connection32_t *)P)->notAvail, sizeof (uint32_t)) : *(uint64_t *)copyin((uintptr_t) &((connection64_t *)P)->notAvail, sizeof (uint64_t)); shared = (curthread->t_procp->p_model == 0x00100000) ? *(uint32_t *)copyin((uintptr_t) &((connection32_t *)P)->shared, sizeof (uint32_t)) : *(uint64_t *)copyin((uintptr_t) &((connection64_t *)P)->shared, sizeof (uint64_t)); pid = (curthread->t_procp->p_model == 0x00100000) ? *(uint32_t *)copyin((uintptr_t) &((connection32_t *)P)->pid, sizeof (uint32_t)) : *(uint64_t *)copyin((uintptr_t) &((connection64_t *)P)->pid, sizeof (uint64_t)); serverAddr = (curthread->t_procp->p_model == 0x00100000) ? copyinstr((uintptr_t)*(uint32_t *)copyin((uintptr_t) &((connection32_t *)P)->serverAddr, sizeof (uint32_t))) : copyinstr((uintptr_t)*(uint64_t *)copyin((uintptr_t) &((connection64_t *)P)->serverAddr, sizeof (uint64_t))); threadID = (curthread->t_procp->p_model == 0x00100000) ? *(uint32_t *)copyin((uintptr_t) &((connection32_t *)P)->threadID, sizeof (uint32_t)) : *(uint64_t *)copyin((uintptr_t) &((connection64_t *)P)->threadID, sizeof (uint64_t)); }; This makes the stucture available in dtrace and I can print the toplevel element fine now. The provider definition looks like this: typedef struct connection { int dummy; } Connection; typedef struct libsldap_connection { int dummy; } libsldap_connection_t; translator libsldap_connection_t < Connection *P > { dummy = P->dummy; }; provider libsldap { probe dbgmessage(char *); probe AddConnection(Connection *connection) : (libsldap_connection_t *connection); probe FindConnection(Connection *connection) : (libsldap_connection_t *connection); probe DropConnection(Connection *connection) : (libsldap_connection_t *connection); }; I can now do things like this: libsldap*:::AddConnection, libsldap*:::FindConnection, libsldap*:::DropConnection { printf("\n"); printf("%s[%d] - connectionId %d\n", execname, pid, args[0]->connectionId); printf("%s[%d] - usedBit %d\n", execname, pid, args[0]->usedBit); printf("%s[%d] - notAvail %d\n", execname, pid, args[0]->notAvail); printf("%s[%d] - shared %d\n", execname, pid, args[0]->shared); printf("%s[%d] - pid %d\n", execname, pid, args[0]->pid); printf("%s[%d] - serveraddr %s\n", execname, pid, args[0]->serverAddr); printf("%s[%d] - threadid %d\n", execname, pid, args[0]->threadID); } But now the fun starts I want to convert more to start with the ???ns_cred_t structure. This is defined like this: /* * Authentication Information */ typedef enum CredLevel { NS_LDAP_CRED_ANON = 0, NS_LDAP_CRED_PROXY = 1, NS_LDAP_CRED_SELF = 2 } CredLevel_t; typedef enum AuthType { NS_LDAP_AUTH_NONE = 0, NS_LDAP_AUTH_SIMPLE = 1, NS_LDAP_AUTH_SASL = 2, NS_LDAP_AUTH_TLS = 3, /* implied SASL usage */ NS_LDAP_AUTH_ATLS = 4 /* implied SASL usage */ } AuthType_t; typedef enum TlsType { NS_LDAP_TLS_NONE = 0, NS_LDAP_TLS_SIMPLE = 1, NS_LDAP_TLS_SASL = 2 } TlsType_t; typedef enum SaslMech { NS_LDAP_SASL_NONE = 0, /* No SASL mechanism */ NS_LDAP_SASL_CRAM_MD5 = 1, NS_LDAP_SASL_DIGEST_MD5 = 2, NS_LDAP_SASL_EXTERNAL = 3, /* currently not supported */ NS_LDAP_SASL_GSSAPI = 4, NS_LDAP_SASL_SPNEGO = 5 /* currently not supported */ } SaslMech_t; typedef enum SaslOpt { NS_LDAP_SASLOPT_NONE = 0, NS_LDAP_SASLOPT_INT = 1, NS_LDAP_SASLOPT_PRIV = 2 } SaslOpt_t; typedef enum PrefOnly { NS_LDAP_PREF_FALSE = 0, NS_LDAP_PREF_TRUE = 1 } PrefOnly_t; typedef struct UnixCred { char *userID; /* Unix ID number */ char *passwd; /* password */ } UnixCred_t; typedef struct CertCred { char *path; /* certificate path */ char *passwd; /* password */ char *nickname; /* nickname */ } CertCred_t; typedef struct ns_auth { AuthType_t type; TlsType_t tlstype; SaslMech_t saslmech; SaslOpt_t saslopt; } ns_auth_t; typedef struct ns_cred { ns_auth_t auth; char *hostcertpath; union { UnixCred_t unix_cred; CertCred_t cert_cred; } cred; } ns_cred_t; So I defined much of the enum in D already which was easy. But the the fun starts. I first thought I would write some translators for the different types and the call the appropriate xlate functions to stuff the correct data into the Connection structure but until now that hasn''t give me much joy. When I try to call those translators I get the error my expression is vaiable. So I was wondering should I just expand the dtrace Connection structure with the different subtypes and convert everything in that one translator, or am I missing something obvious. So the question is more or less, should I stick to the structure used in the C-structs and if so how do I make that available in D, if not should I just stuff everything in one big D structure. Please bear with me as I''m new to dtrace, until 2 months ago I did know it exist but never did anything with it. Currently I''m only prototyping the stuff there is nothing final I just am trying to see if I can make the data available so I can get ride of most of the standard debug statements now in the code and move that into a dtrace probe. Marco van Wieringen