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