1 1.30 mlelstv /* $NetBSD: main.c,v 1.30 2022/08/21 07:46:52 mlelstv Exp $ */ 2 1.1 atatat 3 1.1 atatat /* 4 1.28 ad * Copyright (c) 2002, 2003, 2020 The NetBSD Foundation, Inc. 5 1.1 atatat * All rights reserved. 6 1.1 atatat * 7 1.1 atatat * This code is derived from software contributed to The NetBSD Foundation 8 1.1 atatat * by Andrew Brown. 9 1.1 atatat * 10 1.1 atatat * Redistribution and use in source and binary forms, with or without 11 1.1 atatat * modification, are permitted provided that the following conditions 12 1.1 atatat * are met: 13 1.1 atatat * 1. Redistributions of source code must retain the above copyright 14 1.1 atatat * notice, this list of conditions and the following disclaimer. 15 1.1 atatat * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 atatat * notice, this list of conditions and the following disclaimer in the 17 1.1 atatat * documentation and/or other materials provided with the distribution. 18 1.1 atatat * 19 1.1 atatat * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 atatat * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 atatat * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 atatat * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 atatat * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 atatat * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 atatat * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 atatat * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 atatat * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 atatat * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 atatat * POSSIBILITY OF SUCH DAMAGE. 30 1.1 atatat */ 31 1.1 atatat 32 1.1 atatat #include <sys/cdefs.h> 33 1.1 atatat #ifndef lint 34 1.30 mlelstv __RCSID("$NetBSD: main.c,v 1.30 2022/08/21 07:46:52 mlelstv Exp $"); 35 1.1 atatat #endif 36 1.1 atatat 37 1.1 atatat #include <sys/param.h> 38 1.1 atatat 39 1.1 atatat #ifndef __NetBSD_Version__ 40 1.1 atatat #error go away, you fool 41 1.1 atatat #elif (__NetBSD_Version__ < 105000000) 42 1.1 atatat #error only works with uvm 43 1.1 atatat #endif 44 1.1 atatat 45 1.1 atatat #include <fcntl.h> 46 1.1 atatat #include <errno.h> 47 1.1 atatat #include <unistd.h> 48 1.1 atatat #include <limits.h> 49 1.1 atatat #include <string.h> 50 1.21 christos #include <signal.h> 51 1.26 christos #include <util.h> 52 1.1 atatat 53 1.1 atatat #include "pmap.h" 54 1.1 atatat #include "main.h" 55 1.1 atatat 56 1.1 atatat struct cache_head lcache; 57 1.1 atatat void *uvm_vnodeops, *uvm_deviceops, *aobj_pager, *ubc_pager; 58 1.28 ad struct vm_map *kmem_map, *phys_map, *exec_map, *pager_map; 59 1.28 ad struct vm_map *st_map, *pt_map, *module_map, *buf_map; 60 1.28 ad u_long kernel_map_addr; 61 1.5 atatat int debug, verbose, recurse, page_size; 62 1.1 atatat int print_all, print_map, print_maps, print_solaris, print_ddb; 63 1.30 mlelstv int tree; 64 1.1 atatat rlim_t maxssiz; 65 1.1 atatat 66 1.1 atatat struct nlist ksyms[] = { 67 1.20 lukem { "_maxsmap", 0, 0, 0, 0 }, 68 1.1 atatat #define NL_MAXSSIZ 0 69 1.20 lukem { "_uvm_vnodeops", 0, 0, 0, 0 }, 70 1.1 atatat #define NL_UVM_VNODEOPS 1 71 1.20 lukem { "_uvm_deviceops", 0, 0, 0, 0 }, 72 1.1 atatat #define NL_UVM_DEVICEOPS 2 73 1.20 lukem { "_aobj_pager", 0, 0, 0, 0 }, 74 1.1 atatat #define NL_AOBJ_PAGER 3 75 1.20 lukem { "_ubc_pager", 0, 0, 0, 0 }, 76 1.1 atatat #define NL_UBC_PAGER 4 77 1.20 lukem { "_kernel_map", 0, 0, 0, 0 }, 78 1.1 atatat #define NL_KERNEL_MAP 5 79 1.20 lukem { NULL, 0, 0, 0, 0 } 80 1.1 atatat }; 81 1.1 atatat 82 1.1 atatat struct nlist kmaps[] = { 83 1.20 lukem { "_kmem_map", 0, 0, 0, 0 }, 84 1.4 atatat #define NL_kmem_map 0 85 1.20 lukem { "_phys_map", 0, 0, 0, 0 }, 86 1.28 ad #define NL_phys_map 1 87 1.20 lukem { "_exec_map", 0, 0, 0, 0 }, 88 1.28 ad #define NL_exec_map 2 89 1.20 lukem { "_pager_map", 0, 0, 0, 0 }, 90 1.28 ad #define NL_pager_map 3 91 1.20 lukem { "_st_map", 0, 0, 0, 0 }, 92 1.28 ad #define NL_st_map 4 93 1.20 lukem { "_pt_map", 0, 0, 0, 0 }, 94 1.28 ad #define NL_pt_map 5 95 1.28 ad { "_module_map", 0, 0, 0, 0 }, 96 1.28 ad #define NL_module_map 6 97 1.20 lukem { "_buf_map", 0, 0, 0, 0 }, 98 1.28 ad #define NL_buf_map 7 99 1.20 lukem { NULL, 0, 0, 0, 0 }, 100 1.1 atatat }; 101 1.1 atatat 102 1.7 atatat #define VMSPACE_ADDRESS 1 103 1.7 atatat #define VM_MAP_ADDRESS 2 104 1.7 atatat #define VM_MAP_ENTRY_ADDRESS 3 105 1.7 atatat #define AMAP_ADDRESS 4 106 1.7 atatat 107 1.1 atatat void check_fd(int); 108 1.1 atatat void load_symbols(kvm_t *); 109 1.20 lukem void cache_enter(u_long, struct namecache *); 110 1.1 atatat 111 1.1 atatat int 112 1.1 atatat main(int argc, char *argv[]) 113 1.1 atatat { 114 1.1 atatat kvm_t *kd; 115 1.1 atatat pid_t pid; 116 1.23 jym uid_t uid; 117 1.7 atatat int which, many, ch, rc; 118 1.1 atatat char errbuf[_POSIX2_LINE_MAX + 1]; 119 1.1 atatat struct kinfo_proc2 *kproc; 120 1.7 atatat char *kmem, *kernel, *t; 121 1.2 atatat gid_t egid; 122 1.7 atatat struct kbit kbit, *vmspace; 123 1.7 atatat u_long address; 124 1.2 atatat 125 1.29 chs uid = getuid(); 126 1.2 atatat egid = getegid(); 127 1.2 atatat if (setegid(getgid()) == -1) 128 1.2 atatat err(1, "failed to reset privileges"); 129 1.1 atatat 130 1.1 atatat check_fd(STDIN_FILENO); 131 1.1 atatat check_fd(STDOUT_FILENO); 132 1.1 atatat check_fd(STDERR_FILENO); 133 1.1 atatat 134 1.1 atatat pid = -1; 135 1.7 atatat which = verbose = debug = 0; 136 1.1 atatat print_all = print_map = print_maps = print_solaris = print_ddb = 0; 137 1.30 mlelstv tree = 0; 138 1.1 atatat recurse = 0; 139 1.1 atatat kmem = kernel = NULL; 140 1.7 atatat address = 0; 141 1.7 atatat vmspace = &kbit; 142 1.1 atatat 143 1.30 mlelstv while ((ch = getopt(argc, argv, "A:aD:dE:lM:mN:Pp:RrS:stV:vx")) != -1) { 144 1.1 atatat switch (ch) { 145 1.7 atatat case 'A': 146 1.7 atatat case 'E': 147 1.7 atatat case 'S': 148 1.7 atatat case 'V': 149 1.7 atatat if (which != 0) 150 1.7 atatat errx(1, "use only one of -A, -E, -S, or -V"); 151 1.7 atatat errno = 0; 152 1.7 atatat address = strtoul(optarg, &t, 0); 153 1.7 atatat if (*t != '\0') 154 1.7 atatat errx(1, "%s is not a valid address", optarg); 155 1.7 atatat if (errno != 0) 156 1.7 atatat err(1, "%s is not a valid address", optarg); 157 1.7 atatat switch (ch) { 158 1.7 atatat case 'A': which = AMAP_ADDRESS; break; 159 1.7 atatat case 'E': which = VM_MAP_ENTRY_ADDRESS; break; 160 1.7 atatat case 'S': which = VMSPACE_ADDRESS; break; 161 1.7 atatat case 'V': which = VM_MAP_ADDRESS; break; 162 1.7 atatat } 163 1.7 atatat break; 164 1.1 atatat case 'a': 165 1.1 atatat print_all = 1; 166 1.1 atatat break; 167 1.1 atatat case 'd': 168 1.1 atatat print_ddb = 1; 169 1.1 atatat break; 170 1.1 atatat case 'D': 171 1.7 atatat errno = 0; 172 1.7 atatat debug = strtoul(optarg, &t, 0); 173 1.7 atatat if (*t != '\0') 174 1.7 atatat errx(1, "%s is not a valid number", optarg); 175 1.7 atatat if (errno != 0) 176 1.7 atatat err(1, "%s is not a valid number", optarg); 177 1.1 atatat break; 178 1.1 atatat case 'l': 179 1.1 atatat print_maps = 1; 180 1.1 atatat break; 181 1.1 atatat case 'm': 182 1.1 atatat print_map = 1; 183 1.1 atatat break; 184 1.1 atatat case 'M': 185 1.1 atatat kmem = optarg; 186 1.1 atatat break; 187 1.1 atatat case 'N': 188 1.1 atatat kernel = optarg; 189 1.1 atatat break; 190 1.1 atatat case 'p': 191 1.7 atatat errno = 0; 192 1.7 atatat pid = strtol(optarg, &t, 0); 193 1.7 atatat if (pid < 0) 194 1.7 atatat errno = EINVAL; 195 1.7 atatat if (*t != '\0') 196 1.7 atatat errx(1, "%s is not a valid pid", optarg); 197 1.7 atatat if (errno != 0) 198 1.7 atatat err(1, "%s is not a valid pid", optarg); 199 1.1 atatat break; 200 1.1 atatat case 'P': 201 1.1 atatat pid = getpid(); 202 1.1 atatat break; 203 1.1 atatat case 'R': 204 1.1 atatat recurse = 1; 205 1.1 atatat break; 206 1.1 atatat case 's': 207 1.1 atatat print_solaris = 1; 208 1.1 atatat break; 209 1.30 mlelstv case 't': 210 1.30 mlelstv tree = 1; 211 1.30 mlelstv break; 212 1.1 atatat case 'v': 213 1.1 atatat verbose++; 214 1.1 atatat break; 215 1.1 atatat case 'r': 216 1.1 atatat case 'x': 217 1.1 atatat errx(1, "-%c option not implemented, sorry", optopt); 218 1.1 atatat /*NOTREACHED*/ 219 1.1 atatat case '?': 220 1.1 atatat default: 221 1.30 mlelstv fprintf(stderr, "usage: %s [-adlmPRstv] [-A address] " 222 1.7 atatat "[-D number] [-E address] [-M core]\n" 223 1.8 wiz "\t[-N system] [-p pid] [-S address] " 224 1.8 wiz "[-V address] [pid ...]\n", 225 1.1 atatat getprogname()); 226 1.1 atatat exit(1); 227 1.1 atatat } 228 1.1 atatat } 229 1.1 atatat argc -= optind; 230 1.1 atatat argv += optind; 231 1.1 atatat 232 1.1 atatat /* more than one "process" to dump? */ 233 1.1 atatat many = (argc > 1 - (pid == -1 ? 0 : 1)) ? 1 : 0; 234 1.1 atatat 235 1.1 atatat /* apply default */ 236 1.1 atatat if (print_all + print_map + print_maps + print_solaris + 237 1.1 atatat print_ddb == 0) 238 1.1 atatat print_solaris = 1; 239 1.2 atatat 240 1.29 chs if ((kernel != NULL || kmem != NULL || address != 0 || 241 1.29 chs print_ddb || debug) && uid != 0) 242 1.29 chs errx(1, "one or more options specified is restricted to root"); 243 1.29 chs 244 1.29 chs /* get privs back since it appears to be safe. */ 245 1.29 chs rc = setegid(egid); 246 1.2 atatat if (rc == -1) 247 1.2 atatat err(1, "failed to reset privileges"); 248 1.1 atatat 249 1.1 atatat /* start by opening libkvm */ 250 1.1 atatat kd = kvm_openfiles(kernel, kmem, NULL, O_RDONLY, errbuf); 251 1.9 atatat 252 1.9 atatat /* we're completely done with privileges now */ 253 1.9 atatat rc = setgid(getgid()); 254 1.9 atatat if (rc == -1) 255 1.9 atatat err(1, "failed to reset privileges"); 256 1.9 atatat 257 1.9 atatat /* print the kvm_open error, if any */ 258 1.1 atatat errbuf[_POSIX2_LINE_MAX] = '\0'; 259 1.1 atatat if (kd == NULL) 260 1.1 atatat errx(1, "%s", errbuf); 261 1.1 atatat 262 1.1 atatat /* get "bootstrap" addresses from kernel */ 263 1.1 atatat load_symbols(kd); 264 1.1 atatat 265 1.7 atatat if (address) { 266 1.7 atatat struct kbit kbit2, *at = &kbit2; 267 1.7 atatat 268 1.7 atatat memset(vmspace, 0, sizeof(*vmspace)); 269 1.7 atatat A(at) = address; 270 1.16 atatat S(at) = (size_t)-1; 271 1.7 atatat 272 1.7 atatat switch (which) { 273 1.7 atatat case VMSPACE_ADDRESS: 274 1.7 atatat /* (kd, kproc, vmspace, thing) */ 275 1.7 atatat (*process_map)(kd, NULL, at, "vm_map"); 276 1.7 atatat break; 277 1.7 atatat case VM_MAP_ADDRESS: 278 1.7 atatat /* (kd, proc, vmspace, vm_map, thing) */ 279 1.7 atatat (*dump_vm_map)(kd, NULL, vmspace, at, "vm_map"); 280 1.7 atatat break; 281 1.7 atatat case VM_MAP_ENTRY_ADDRESS: 282 1.7 atatat /* (kd, proc, vmspace, vm_map_entry, 0) */ 283 1.7 atatat (*dump_vm_map_entry)(kd, NULL, vmspace, at, 0); 284 1.7 atatat break; 285 1.7 atatat case AMAP_ADDRESS: 286 1.7 atatat /* (kd, amap) */ 287 1.7 atatat (*dump_amap)(kd, at); 288 1.7 atatat break; 289 1.7 atatat } 290 1.7 atatat exit(0); 291 1.7 atatat } 292 1.1 atatat 293 1.1 atatat do { 294 1.1 atatat if (pid == -1) { 295 1.1 atatat if (argc == 0) 296 1.1 atatat pid = getppid(); 297 1.1 atatat else { 298 1.7 atatat errno = 0; 299 1.7 atatat pid = strtol(argv[0], &t, 0); 300 1.7 atatat if (pid < 0) 301 1.7 atatat errno = EINVAL; 302 1.7 atatat if (*t != '\0') 303 1.7 atatat errx(1, "%s is not a valid pid", 304 1.7 atatat argv[0]); 305 1.7 atatat if (errno != 0) 306 1.7 atatat err(1, "%s is not a valid pid", 307 1.7 atatat argv[0]); 308 1.1 atatat argv++; 309 1.1 atatat argc--; 310 1.1 atatat } 311 1.1 atatat } 312 1.1 atatat 313 1.23 jym errno = 0; 314 1.1 atatat /* find the process id */ 315 1.23 jym if (pid == 0) { 316 1.1 atatat kproc = NULL; 317 1.23 jym if (uid != 0) { 318 1.23 jym /* only root can print kernel mappings */ 319 1.23 jym errno = EPERM; 320 1.23 jym } 321 1.23 jym } else { 322 1.1 atatat kproc = kvm_getproc2(kd, KERN_PROC_PID, pid, 323 1.24 jym sizeof(struct kinfo_proc2), &rc); 324 1.1 atatat if (kproc == NULL || rc == 0) { 325 1.1 atatat errno = ESRCH; 326 1.23 jym } else if (uid != 0 && uid != kproc->p_uid) { 327 1.23 jym /* 328 1.23 jym * only the real owner of the process and 329 1.23 jym * root can print process mappings 330 1.23 jym */ 331 1.23 jym errno = EPERM; 332 1.1 atatat } 333 1.1 atatat } 334 1.1 atatat 335 1.23 jym if (errno != 0) { 336 1.23 jym warn("%d", pid); 337 1.23 jym pid = -1; 338 1.23 jym continue; 339 1.23 jym } 340 1.23 jym 341 1.1 atatat /* dump it */ 342 1.1 atatat if (many) { 343 1.24 jym if (kproc != NULL) 344 1.1 atatat printf("process %d:\n", kproc->p_pid); 345 1.1 atatat else 346 1.1 atatat printf("kernel:\n"); 347 1.1 atatat } 348 1.1 atatat 349 1.7 atatat (*process_map)(kd, kproc, vmspace, NULL); 350 1.1 atatat pid = -1; 351 1.1 atatat } while (argc > 0); 352 1.1 atatat 353 1.1 atatat /* done. go away. */ 354 1.1 atatat rc = kvm_close(kd); 355 1.1 atatat if (rc == -1) 356 1.1 atatat err(1, "kvm_close"); 357 1.1 atatat 358 1.1 atatat return (0); 359 1.1 atatat } 360 1.1 atatat 361 1.1 atatat void 362 1.1 atatat check_fd(int fd) 363 1.1 atatat { 364 1.1 atatat struct stat st; 365 1.1 atatat int n; 366 1.1 atatat 367 1.1 atatat if (fstat(fd, &st) == -1) { 368 1.1 atatat (void)close(fd); 369 1.1 atatat n = open("/dev/null", O_RDWR); 370 1.1 atatat if (n == fd || n == -1) 371 1.1 atatat /* we're either done or we can do no more */ 372 1.1 atatat return; 373 1.1 atatat /* if either of these fail, there's not much we can do */ 374 1.1 atatat (void)dup2(n, fd); 375 1.1 atatat (void)close(n); 376 1.1 atatat /* XXX should we exit if it fails? */ 377 1.1 atatat } 378 1.1 atatat } 379 1.1 atatat 380 1.1 atatat void 381 1.1 atatat load_symbols(kvm_t *kd) 382 1.1 atatat { 383 1.5 atatat int rc, i, mib[2]; 384 1.6 he size_t sz; 385 1.1 atatat 386 1.1 atatat rc = kvm_nlist(kd, &ksyms[0]); 387 1.1 atatat if (rc != 0) { 388 1.1 atatat for (i = 0; ksyms[i].n_name != NULL; i++) 389 1.1 atatat if (ksyms[i].n_value == 0) 390 1.3 atatat warnx("symbol %s: not found", ksyms[i].n_name); 391 1.1 atatat exit(1); 392 1.1 atatat } 393 1.1 atatat 394 1.1 atatat uvm_vnodeops = (void*)ksyms[NL_UVM_VNODEOPS].n_value; 395 1.1 atatat uvm_deviceops = (void*)ksyms[NL_UVM_DEVICEOPS].n_value; 396 1.1 atatat aobj_pager = (void*)ksyms[NL_AOBJ_PAGER].n_value; 397 1.1 atatat ubc_pager = (void*)ksyms[NL_UBC_PAGER].n_value; 398 1.1 atatat 399 1.1 atatat _KDEREF(kd, ksyms[NL_MAXSSIZ].n_value, &maxssiz, 400 1.1 atatat sizeof(maxssiz)); 401 1.1 atatat _KDEREF(kd, ksyms[NL_KERNEL_MAP].n_value, &kernel_map_addr, 402 1.1 atatat sizeof(kernel_map_addr)); 403 1.1 atatat 404 1.1 atatat /* 405 1.1 atatat * Some of these may be missing from some platforms, for 406 1.1 atatat * example sparc, sh3, and most powerpc platforms don't 407 1.4 atatat * have a "phys_map", etc. 408 1.1 atatat */ 409 1.1 atatat (void)kvm_nlist(kd, &kmaps[0]); 410 1.4 atatat 411 1.14 atatat #define get_map_address(m) do {\ 412 1.17 yamt if (kmaps[__CONCAT(NL_,m)].n_value != 0) \ 413 1.17 yamt _KDEREF(kd, kmaps[__CONCAT(NL_,m)].n_value, &m, sizeof(m)); \ 414 1.16 atatat } while (0/*CONSTCOND*/) 415 1.4 atatat 416 1.4 atatat get_map_address(kmem_map); 417 1.4 atatat get_map_address(phys_map); 418 1.4 atatat get_map_address(exec_map); 419 1.4 atatat get_map_address(pager_map); 420 1.4 atatat get_map_address(st_map); 421 1.4 atatat get_map_address(pt_map); 422 1.28 ad get_map_address(module_map); 423 1.14 atatat get_map_address(buf_map); 424 1.5 atatat 425 1.5 atatat mib[0] = CTL_HW; 426 1.5 atatat mib[1] = HW_PAGESIZE; 427 1.6 he sz = sizeof(page_size); 428 1.6 he if (sysctl(&mib[0], 2, &page_size, &sz, NULL, 0) == -1) 429 1.5 atatat err(1, "sysctl: hw.pagesize"); 430 1.4 atatat } 431 1.4 atatat 432 1.4 atatat const char * 433 1.4 atatat mapname(void *addr) 434 1.4 atatat { 435 1.4 atatat 436 1.4 atatat if (addr == (void*)kernel_map_addr) 437 1.4 atatat return ("kernel_map"); 438 1.4 atatat else if (addr == kmem_map) 439 1.4 atatat return ("kmem_map"); 440 1.4 atatat else if (addr == phys_map) 441 1.4 atatat return ("phys_map"); 442 1.4 atatat else if (addr == exec_map) 443 1.4 atatat return ("exec_map"); 444 1.4 atatat else if (addr == pager_map) 445 1.4 atatat return ("pager_map"); 446 1.4 atatat else if (addr == st_map) 447 1.4 atatat return ("st_map"); 448 1.4 atatat else if (addr == pt_map) 449 1.4 atatat return ("pt_map"); 450 1.28 ad else if (addr == module_map) 451 1.28 ad return ("module_map"); 452 1.14 atatat else if (addr == buf_map) 453 1.14 atatat return ("buf_map"); 454 1.4 atatat else 455 1.4 atatat return (NULL); 456 1.1 atatat } 457