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 int 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 isnull, int tab, struct namecache *, 81 const char *); 82 83 static long num_unres; 84 static long num_leafs; 85 static long num_neg; 86 static long num_cache; 87 88 int 89 main(int ac, char **av) 90 { 91 struct nchandle nch; 92 struct mount mntinfo; 93 struct mount *mntptr; 94 struct mntlist list; 95 kvm_t *kd; 96 const char *corefile = NULL; 97 const char *sysfile = NULL; 98 const char *path; 99 int ch; 100 int i; 101 int n; 102 int isnull; 103 char mntpath[1024]; 104 105 while ((ch = getopt(ac, av, "M:N:")) != -1) { 106 switch(ch) { 107 case 'M': 108 corefile = optarg; 109 break; 110 case 'N': 111 sysfile = optarg; 112 break; 113 default: 114 fprintf(stderr, "%s [-M core] [-N system]\n", av[0]); 115 exit(1); 116 } 117 } 118 ac -= optind; 119 av += optind; 120 121 if ((kd = kvm_open(sysfile, corefile, NULL, O_RDONLY, "kvm:")) == NULL) { 122 perror("kvm_open"); 123 exit(1); 124 } 125 if (kvm_nlist(kd, Nl) != 0) { 126 perror("kvm_nlist"); 127 exit(1); 128 } 129 kkread(kd, Nl[0].n_value, &nch, sizeof(nch)); 130 kkread(kd, Nl[1].n_value, &list, sizeof(list)); 131 132 mntptr = TAILQ_FIRST(&list); 133 while (mntptr) { 134 kkread(kd, (long)mntptr, &mntinfo, sizeof(mntinfo)); 135 printf("MOUNT %p ", mntptr); 136 if (mntinfo.mnt_vfc) { 137 isnull = printvfc(kd, mntinfo.mnt_vfc); 138 printf(" "); 139 } else { 140 isnull = 0; 141 } 142 mntpath[sizeof(mntpath)-1] = 0; 143 path = getncppath(kd, &mntinfo.mnt_ncmounton, 144 mntpath, sizeof(mntpath) - 1); 145 printf("ON %s\n", path); 146 if (ac == 0) { 147 dumpncp(kd, isnull, 0, mntinfo.mnt_ncmountpt.ncp, NULL); 148 } else { 149 n = strlen(path); 150 for (i = 0; i < ac; ++i) { 151 if (strncmp(path, av[i], n) == 0) { 152 dumpncp(kd, isnull, 0, 153 mntinfo.mnt_ncmountpt.ncp, av[i] + n); 154 } 155 } 156 } 157 mntptr = TAILQ_NEXT(&mntinfo, mnt_list); 158 } 159 160 printf("numunres = %ld\n", num_unres); 161 printf("numleafs = %ld\n", num_leafs); 162 printf("numcache = %ld\n", num_cache); 163 printf("numneg = %ld\n", num_neg); 164 } 165 166 static void 167 dumpncp(kvm_t *kd, int isnull, int tab, 168 struct namecache *ncptr, const char *path) 169 { 170 struct namecache ncp; 171 struct namecache *ncscan; 172 const char *ptr; 173 int haschildren; 174 char name[256]; 175 176 kkread(kd, (u_long)ncptr, &ncp, sizeof(ncp)); 177 if (ncp.nc_nlen < sizeof(name)) { 178 kkread(kd, (u_long)ncp.nc_name, name, ncp.nc_nlen); 179 name[ncp.nc_nlen] = 0; 180 } else { 181 name[0] = 0; 182 } 183 184 if (isnull == 0) { 185 if (ncp.nc_parent) { 186 if ((ncp.nc_flag & NCF_UNRESOLVED) && ncp.nc_list.tqh_first == NULL) 187 ++num_unres; 188 if (ncp.nc_list.tqh_first == NULL) 189 ++num_leafs; 190 ++num_cache; 191 } 192 if ((ncp.nc_flag & NCF_UNRESOLVED) == 0 && ncp.nc_vp == NULL) 193 ++num_neg; 194 } 195 196 if (tab == 0) { 197 strcpy(name, "FSROOT"); 198 if (path && *path == '/') 199 ++path; 200 } else if (name[0] == 0) { 201 strcpy(name, "?"); 202 if (path) 203 return; 204 } else if (path) { 205 if ((ptr = strchr(path, '/')) == NULL) 206 ptr = path + strlen(path); 207 if (strlen(name) != ptr - path || 208 bcmp(name, path, ptr - path) != 0 209 ) { 210 return; 211 } 212 path = ptr; 213 if (*path == '/') 214 ++path; 215 } 216 if (path && *path == 0) 217 path = NULL; 218 219 if (ncp.nc_list.tqh_first) 220 haschildren = 1; 221 else 222 haschildren = 0; 223 224 if (path) 225 printf("ELM "); 226 else 227 printf("%*.*s%s ", tab, tab, "", name); 228 printf("[ncp=%p par=%p %04x vp=%p", 229 ncptr, ncp.nc_parent, ncp.nc_flag, ncp.nc_vp); 230 if (ncp.nc_timeout) 231 printf(" timo=%d", ncp.nc_timeout); 232 if (ncp.nc_refs) 233 printf(" refs=%d", ncp.nc_refs); 234 if (ncp.nc_generation) 235 printf(" gen=%d", ncp.nc_generation); 236 if ((ncp.nc_flag & NCF_UNRESOLVED) == 0 && ncp.nc_error) 237 printf(" error=%d", ncp.nc_error); 238 if (ncp.nc_flag & NCF_ISMOUNTPT) 239 printf(" MAYBEMOUNT"); 240 if (ncp.nc_lock.lk_count & ~LKC_SHARED) { 241 printf(" LOCKSTATUS(%016lx,td=%p)", 242 ncp.nc_lock.lk_count, ncp.nc_lock.lk_lockholder); 243 } 244 printf("]"); 245 246 if (path) { 247 printf(" %s\n", name); 248 } else { 249 printf("%s\n", haschildren ? " {" : ""); 250 } 251 for (ncscan = ncp.nc_list.tqh_first; ncscan; ncscan = ncp.nc_entry.tqe_next) { 252 kkread(kd, (u_long)ncscan, &ncp, sizeof(ncp)); 253 dumpncp(kd, isnull, (path ? (tab ? tab : 4) : tab + 4), ncscan, path); 254 } 255 if (haschildren && path == NULL) 256 printf("%*.*s}\n", tab, tab, ""); 257 } 258 259 static 260 char * 261 getncppath(kvm_t *kd, struct nchandle *nch, char *base, int bytes) 262 { 263 struct mount mntinfo; 264 struct namecache ncp; 265 struct namecache *ncpptr; 266 267 ncpptr = nch->ncp; 268 while (ncpptr) { 269 kkread(kd, (long)ncpptr, &ncp, sizeof(ncp)); 270 if (ncp.nc_nlen >= bytes) 271 break; 272 kkread(kd, (long)ncp.nc_name, base + bytes - ncp.nc_nlen, ncp.nc_nlen); 273 bytes -= ncp.nc_nlen; 274 if (ncp.nc_parent) { 275 base[--bytes] = '/'; 276 } 277 ncpptr = ncp.nc_parent; 278 } 279 if (nch->mount) { 280 kkread(kd, (long)nch->mount, &mntinfo, sizeof(mntinfo)); 281 if (mntinfo.mnt_ncmounton.mount) 282 return(getncppath(kd, &mntinfo.mnt_ncmounton, base, bytes)); 283 } else if (base[bytes] == 0) { 284 base[--bytes] = '/'; 285 } 286 return(base + bytes); 287 } 288 289 static 290 int 291 printvfc(kvm_t *kd, struct vfsconf *vfc) 292 { 293 struct vfsconf vfcinfo; 294 295 kkread(kd, (long)vfc, &vfcinfo, sizeof(vfcinfo)); 296 printf("%s [type %d]", vfcinfo.vfc_name, vfcinfo.vfc_typenum); 297 298 return (strcmp(vfcinfo.vfc_name, "null") == 0); 299 } 300 301 static void 302 kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes) 303 { 304 if (kvm_read(kd, addr, buf, nbytes) != nbytes) { 305 perror("kvm_read"); 306 exit(1); 307 } 308 } 309 310