open-src/util/mdb-tools/src/modules/Xserver_clients.c
changeset 492 abfa40ff15ef
child 851 d428083dbbdd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/open-src/util/mdb-tools/src/modules/Xserver_clients.c	Fri Aug 08 16:28:28 2008 -0700
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use subject to license terms.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, and/or sell copies of the Software, and to permit persons
+ * to whom the Software is furnished to do so, provided that the above
+ * copyright notice(s) and this permission notice appear in all copies of
+ * the Software and that both the above copyright notice(s) and this
+ * permission notice appear in supporting documentation.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+ * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+ * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * 
+ * Except as contained in this notice, the name of a copyright holder
+ * shall not be used in advertising or otherwise to promote the sale, use
+ * or other dealings in this Software without prior written authorization
+ * of the copyright holder.
+ *
+ * @(#)Xserver_clients.c	1.2	08/08/08
+ */
+
+#pragma ident	"@(#)Xserver_clients.c	1.2	08/08/08 SMI"
+
+#include <sys/mdb_modapi.h>
+#include "Xserver_headers.h"
+#include <X11/extensions/interactive.h>
+
+struct client_walk_data {
+    uintptr_t client_next;
+    uintptr_t clients_end;
+    ClientRec client_data;
+};
+
+#ifdef XORG
+/* Xsun has these in a header, Xorg has them in sun-src/IA/interactive.c so
+   we just copy it here for now.   XXX: Move to header in Xorg too. */
+typedef struct _ClientProcessInfo {
+    int count;
+    ConnectionPidPtr pids;
+} ClientProcessRec, * ClientProcessPtr;
+
+typedef struct {
+    ClientProcessPtr    process; /* Process id information */    
+    Bool                wmgr;
+} IAClientPrivateRec, *IAClientPrivatePtr;
+#endif
+
+/*
+ * Initialize the client walker by either using the given starting address,
+ * or reading the value of the server's "clients" pointer.  We also allocate
+ * a  for storage, and save this using the walk_data pointer.
+ */
+static int
+client_walk_init(mdb_walk_state_t *wsp)
+{
+    struct client_walk_data *cwda;
+    short max_clients = 128;
+#ifdef XSUN
+# define MAX_CLIENTS "max_clients"
+#else
+# define MAX_CLIENTS "currentMaxClients"
+#endif
+    
+    if (wsp->walk_addr == NULL) {
+       if (mdb_readvar(&wsp->walk_addr, "clients") == -1) {
+	   mdb_warn("failed to read 'clients'");
+	   return (WALK_ERR);
+       }
+       if (mdb_readvar(&max_clients, MAX_CLIENTS) == -1) {
+	   mdb_warn("failed to read '%s'", MAX_CLIENTS);
+	   return (WALK_ERR);
+       } else {
+	   mdb_printf("%s = %d\n", MAX_CLIENTS, max_clients);
+       }
+    }
+
+    wsp->walk_data = mdb_alloc(sizeof (struct client_walk_data), UM_SLEEP);
+    cwda = (struct client_walk_data *) wsp->walk_data;
+    cwda->clients_end = wsp->walk_addr + (max_clients * (sizeof(void *)));
+    return (WALK_NEXT);
+}
+
+/*
+ * At each step, read a client struct into our private storage, and then invoke
+ * the callback function.  We terminate when we reach the end of the clients
+ * array.
+ */
+static int
+client_walk_step(mdb_walk_state_t *wsp)
+{
+	int status;
+	uintptr_t clientPtr;
+	struct client_walk_data *cwda =
+	  (struct client_walk_data *) wsp->walk_data;
+
+	if (wsp->walk_addr == NULL)
+		return (WALK_DONE);
+
+	do {
+	    if (mdb_vread(&clientPtr, sizeof (void *), wsp->walk_addr) == -1) {
+		mdb_warn("failed to read client table entry at %p", wsp->walk_addr);
+		return (WALK_DONE);
+	    }
+	    if (clientPtr == NULL) {
+#ifdef DEBUG
+		mdb_printf("NULL entry at %p", wsp->walk_addr);
+#endif
+		wsp->walk_addr += sizeof(void *);
+	    }
+	    if (wsp->walk_addr >= cwda->clients_end) {
+#ifdef DEBUG
+		mdb_printf("End of client list at %p", cwda->clients_end);
+#endif
+		return (WALK_DONE);
+	    }
+	} while (clientPtr == NULL);
+
+	if (clientPtr == NULL) {
+	    return (WALK_DONE);
+	}
+
+	if (mdb_vread(&(cwda->client_data), sizeof (ClientRec), (uintptr_t) clientPtr) == -1) {
+		mdb_warn("failed to read client data at %p", wsp->walk_addr);
+		return (WALK_DONE);
+	}
+
+	status = wsp->walk_callback(wsp->walk_addr, &(cwda->client_data),
+	  wsp->walk_cbdata);
+
+	wsp->walk_addr = wsp->walk_addr + sizeof(void *);
+	return (status);
+}
+
+/*
+ * The walker's fini function is invoked at the end of each walk.  Since we
+ * dynamically allocated a proc_t in client_walk_init, we must free it now.
+ */
+static void
+client_walk_fini(mdb_walk_state_t *wsp)
+{
+	mdb_free(wsp->walk_data, sizeof (ClientRec));
+}
+
+static int
+client_pids(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+    uintptr_t clientP;
+    ClientRec client_data;
+    
+	if (argc != 0)
+		return (DCMD_USAGE);
+
+	/*
+	 * If no client address was specified on the command line, we can
+	 * print out all clients by invoking the walker, using this
+	 * dcmd itself as the callback.
+	 */
+	if (!(flags & DCMD_ADDRSPEC)) {
+		if (mdb_walk_dcmd("client_walk", "client_pids",
+		    argc, argv) == -1) {
+			mdb_warn("failed to walk 'client_walk'");
+			return (DCMD_ERR);
+		}
+		return (DCMD_OK);
+	}
+
+	/*
+	 * If this is the first invocation of the command, print a nice
+	 * header line for the output that will follow.
+	 */
+	if (DCMD_HDRSPEC(flags))
+		mdb_printf("CLIENT SEQUENCE #  FD  PIDS\n");
+
+
+	if (mdb_vread(&clientP, sizeof (clientP), addr) == sizeof (clientP)) {
+
+	    if (mdb_vread(&client_data, sizeof (client_data), clientP) == sizeof (client_data)) {
+		mdb_printf("%5d  %10d", client_data.index, client_data.sequence);
+
+		if (client_data.osPrivate != NULL) {
+		    OsCommRec oscomm;
+
+		    if (mdb_vread(&oscomm, sizeof (oscomm),
+		      (uintptr_t)client_data.osPrivate) == sizeof (oscomm)) {
+			ClientProcessPtr cpp;
+#ifdef XORG
+			int IAClientPrivateIndex;
+#endif
+			
+			mdb_printf("%4d ", oscomm.fd);
+
+#ifdef XSUN
+			cpp = oscomm.process;
+#else /* XORG */
+			if (mdb_readvar(&IAClientPrivateIndex,
+					"libIA.so`IAClientPrivateIndex") == -1) {
+			    mdb_warn("failed to read 'IAClientPrivateIndex'");
+			} else {
+			    DevUnion *cppaddr =	&(client_data.devPrivates[IAClientPrivateIndex]);
+			    if (mdb_vread(&cpp, sizeof (cpp), (uintptr_t) cppaddr) != sizeof (cpp)) {
+				cpp = NULL;
+				mdb_warn("failed to read client_data.devPrivates[IAClientPrivateIndex]");
+			    }
+
+			}
+#endif			
+			
+			if (cpp != NULL) {
+			    ClientProcessRec cpr;
+			    ConnectionPidRec pid;
+
+			    if (mdb_vread(&cpr, sizeof (cpr),
+					  (uintptr_t)cpp) == sizeof (cpr)) {
+				int i;
+				uintptr_t pidP = (uintptr_t) cpr.pids;
+
+				for (i = 0; i < cpr.count; i++, pidP += sizeof(pid)) {
+				    if (mdb_vread(&pid, sizeof (pid), pidP) == sizeof (pid)) {
+					mdb_printf("%d ", pid);
+				    } else {
+					mdb_warn("failed to read pid #%d from %p", i, pidP);
+				    }
+				}
+				mdb_printf("\n");
+
+			    } else {
+				mdb_warn("failed to read struct ClientProcessRec at %p", client_data.osPrivate);
+			    }
+			} else {
+			    mdb_printf(" ??? - NULL ClientProcessPtr\n");
+			}
+		    } else {
+			mdb_warn("failed to read struct OsCommRec at %p", client_data.osPrivate);
+		    }
+		} else {
+		    mdb_printf(" ??? - NULL ClientPtr->osPrivate\n");
+		}
+	    } else {
+		mdb_warn("failed to read ClientRec at %p", clientP);
+	    }
+	} else {
+	    mdb_warn("failed to read ClientPtr at %p", addr);
+	}
+
+	return (DCMD_OK);
+}
+
+/*
+ * MDB module linkage information:
+ *
+ * We declare a list of structures describing our dcmds, a list of structures
+ * describing our walkers, and a function named _mdb_init to return a pointer
+ * to our module information.
+ */
+
+static const mdb_dcmd_t dcmds[] = {
+	{ "client_pids", NULL, "client process list", client_pids },
+	{ NULL }
+};
+
+static const mdb_walker_t walkers[] = {
+	{ "client_walk", "walk list of clients connected to Xsun",
+		client_walk_init, client_walk_step, client_walk_fini },
+	{ NULL }
+};
+
+static const mdb_modinfo_t modinfo = {
+	MDB_API_VERSION, dcmds, walkers
+};
+
+const mdb_modinfo_t *
+_mdb_init(void)
+{
+	return (&modinfo);
+}