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


_______________________________________________
dtrace-discuss mailing list
[email protected]

Reply via email to