1 /* 2 * NCPTRACE.C 3 * 4 * cc -I/usr/src/sys ncptrace.c -o /usr/local/bin/ncptrace -lkvm 5 * 6 * ncptrace 7 * ncptrace [path] 8 * 9 * Trace and dump the kernel namecache hierarchy. If a path is specified 10 * the trace begins there, otherwise the trace begins at the root. 11 * 12 * 13 * Copyright (c) 2004 The DragonFly Project. All rights reserved. 14 * 15 * This code is derived from software contributed to The DragonFly Project 16 * by Matthew Dillon <dillon@backplane.com> 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions 20 * are met: 21 * 22 * 1. Redistributions of source code must retain the above copyright 23 * notice, this list of conditions and the following disclaimer. 24 * 2. Redistributions in binary form must reproduce the above copyright 25 * notice, this list of conditions and the following disclaimer in 26 * the documentation and/or other materials provided with the 27 * distribution. 28 * 3. Neither the name of The DragonFly Project nor the names of its 29 * contributors may be used to endorse or promote products derived 30 * from this software without specific, prior written permission. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 35 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 36 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 37 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 38 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 39 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 40 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 41 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 42 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 43 * SUCH DAMAGE. 44 * 45 * $DragonFly: src/test/debug/ncptrace.c,v 1.7 2007/05/06 20:45:01 dillon Exp $ 46 */ 47 48 #define _KERNEL_STRUCTURES 49 #include <sys/param.h> 50 #include <sys/user.h> 51 #include <sys/malloc.h> 52 #include <sys/signalvar.h> 53 #include <sys/vnode.h> 54 #include <sys/namecache.h> 55 #include <sys/mount.h> 56 57 #include <vm/vm.h> 58 #include <vm/vm_page.h> 59 #include <vm/vm_kern.h> 60 #include <vm/swap_pager.h> 61 #include <vm/vnode_pager.h> 62 63 #include <stdio.h> 64 #include <stdlib.h> 65 #include <string.h> 66 #include <fcntl.h> 67 #include <kvm.h> 68 #include <nlist.h> 69 #include <getopt.h> 70 71 struct nlist Nl[] = { 72 { "_rootnch" }, 73 { "_mountlist" }, 74 { NULL } 75 }; 76 77 static char *getncppath(kvm_t *kd, struct nchandle *nch, char *buf, int bytes); 78 static void printvfc(kvm_t *kd, struct vfsconf *vfc); 79 static void kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes); 80 static void dumpncp(kvm_t *kd, int tab, struct namecache *, const char *); 81 82 int 83 main(int ac, char **av) 84 { 85 struct nchandle nch; 86 struct mount mntinfo; 87 struct mount *mntptr; 88 struct mntlist list; 89 kvm_t *kd; 90 const char *corefile = NULL; 91 const char *sysfile = NULL; 92 const char *path; 93 int ch; 94 int i; 95 int n; 96 char mntpath[1024]; 97 98 while ((ch = getopt(ac, av, "M:N:")) != -1) { 99 switch(ch) { 100 case 'M': 101 corefile = optarg; 102 break; 103 case 'N': 104 sysfile = optarg; 105 break; 106 default: 107 fprintf(stderr, "%s [-M core] [-N system]\n", av[0]); 108 exit(1); 109 } 110 } 111 ac -= optind; 112 av += optind; 113 114 if ((kd = kvm_open(sysfile, corefile, NULL, O_RDONLY, "kvm:")) == NULL) { 115 perror("kvm_open"); 116 exit(1); 117 } 118 if (kvm_nlist(kd, Nl) != 0) { 119 perror("kvm_nlist"); 120 exit(1); 121 } 122 kkread(kd, Nl[0].n_value, &nch, sizeof(nch)); 123 kkread(kd, Nl[1].n_value, &list, sizeof(list)); 124 125 mntptr = TAILQ_FIRST(&list); 126 while (mntptr) { 127 kkread(kd, (long)mntptr, &mntinfo, sizeof(mntinfo)); 128 printf("MOUNT %p ", mntptr); 129 if (mntinfo.mnt_vfc) { 130 printvfc(kd, mntinfo.mnt_vfc); 131 printf(" "); 132 } 133 mntpath[sizeof(mntpath)-1] = 0; 134 path = getncppath(kd, &mntinfo.mnt_ncmounton, 135 mntpath, sizeof(mntpath) - 1); 136 printf("ON %s\n", path); 137 if (ac == 0) { 138 dumpncp(kd, 0, mntinfo.mnt_ncmountpt.ncp, NULL); 139 } else { 140 n = strlen(path); 141 for (i = 0; i < ac; ++i) { 142 if (strncmp(path, av[i], n) == 0) { 143 dumpncp(kd, 0, mntinfo.mnt_ncmountpt.ncp, av[i] + n); 144 } 145 } 146 } 147 mntptr = TAILQ_NEXT(&mntinfo, mnt_list); 148 } 149 } 150 151 static void 152 dumpncp(kvm_t *kd, int tab, struct namecache *ncptr, const char *path) 153 { 154 struct namecache ncp; 155 struct namecache *ncscan; 156 const char *ptr; 157 int haschildren; 158 char name[256]; 159 160 kkread(kd, (u_long)ncptr, &ncp, sizeof(ncp)); 161 if (ncp.nc_nlen < sizeof(name)) { 162 kkread(kd, (u_long)ncp.nc_name, name, ncp.nc_nlen); 163 name[ncp.nc_nlen] = 0; 164 } else { 165 name[0] = 0; 166 } 167 if (tab == 0) { 168 strcpy(name, "FSROOT"); 169 if (path && *path == '/') 170 ++path; 171 } else if (name[0] == 0) { 172 strcpy(name, "?"); 173 if (path) 174 return; 175 } else if (path) { 176 if ((ptr = strchr(path, '/')) == NULL) 177 ptr = path + strlen(path); 178 if (strlen(name) != ptr - path || 179 bcmp(name, path, ptr - path) != 0 180 ) { 181 return; 182 } 183 path = ptr; 184 if (*path == '/') 185 ++path; 186 } 187 if (path && *path == 0) 188 path = NULL; 189 190 if (ncp.nc_list.tqh_first) 191 haschildren = 1; 192 else 193 haschildren = 0; 194 195 if (path) 196 printf("ELM "); 197 else 198 printf("%*.*s%s ", tab, tab, "", name); 199 printf("[ncp=%p par=%p %04x vp=%p", 200 ncptr, ncp.nc_parent, ncp.nc_flag, ncp.nc_vp); 201 if (ncp.nc_timeout) 202 printf(" timo=%d", ncp.nc_timeout); 203 if (ncp.nc_refs) 204 printf(" refs=%d", ncp.nc_refs); 205 if ((ncp.nc_flag & NCF_UNRESOLVED) == 0 && ncp.nc_error) 206 printf(" error=%d", ncp.nc_error); 207 if (ncp.nc_flag & NCF_ISMOUNTPT) 208 printf(" MAYBEMOUNT"); 209 if (ncp.nc_lockstatus) 210 printf(" LOCKSTATUS(%08x,td=%p)", ncp.nc_lockstatus, ncp.nc_locktd); 211 printf("]"); 212 213 if (path) { 214 printf(" %s\n", name); 215 } else { 216 printf("%s\n", haschildren ? " {" : ""); 217 } 218 for (ncscan = ncp.nc_list.tqh_first; ncscan; ncscan = ncp.nc_entry.tqe_next) { 219 kkread(kd, (u_long)ncscan, &ncp, sizeof(ncp)); 220 dumpncp(kd, (path ? (tab ? tab : 4) : tab + 4), ncscan, path); 221 } 222 if (haschildren && path == NULL) 223 printf("%*.*s}\n", tab, tab, ""); 224 } 225 226 static 227 char * 228 getncppath(kvm_t *kd, struct nchandle *nch, char *base, int bytes) 229 { 230 struct mount mntinfo; 231 struct namecache ncp; 232 struct namecache *ncpptr; 233 234 ncpptr = nch->ncp; 235 while (ncpptr) { 236 kkread(kd, (long)ncpptr, &ncp, sizeof(ncp)); 237 if (ncp.nc_nlen >= bytes) 238 break; 239 kkread(kd, (long)ncp.nc_name, base + bytes - ncp.nc_nlen, ncp.nc_nlen); 240 bytes -= ncp.nc_nlen; 241 if (ncp.nc_parent) { 242 base[--bytes] = '/'; 243 } 244 ncpptr = ncp.nc_parent; 245 } 246 if (nch->mount) { 247 kkread(kd, (long)nch->mount, &mntinfo, sizeof(mntinfo)); 248 if (mntinfo.mnt_ncmounton.mount) 249 return(getncppath(kd, &mntinfo.mnt_ncmounton, base, bytes)); 250 } else if (base[bytes] == 0) { 251 base[--bytes] = '/'; 252 } 253 return(base + bytes); 254 } 255 256 static 257 void 258 printvfc(kvm_t *kd, struct vfsconf *vfc) 259 { 260 struct vfsconf vfcinfo; 261 262 kkread(kd, (long)vfc, &vfcinfo, sizeof(vfcinfo)); 263 printf("%s [type %d]", vfcinfo.vfc_name, vfcinfo.vfc_typenum); 264 } 265 266 static void 267 kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes) 268 { 269 if (kvm_read(kd, addr, buf, nbytes) != nbytes) { 270 perror("kvm_read"); 271 exit(1); 272 } 273 } 274 275