]>
Commit | Line | Data |
---|---|---|
cf37c299 | 1 | /* |
887d5eed | 2 | * Copyright (c) 2016 Apple Inc. All rights reserved. |
cf37c299 A |
3 | */ |
4 | ||
5 | #include "options.h" | |
6 | #include "utils.h" | |
7 | #include "region.h" | |
8 | ||
9 | #include <stdio.h> | |
10 | #include <string.h> | |
11 | #include <strings.h> | |
12 | #include <stdlib.h> | |
13 | #include <stdarg.h> | |
14 | #include <unistd.h> | |
15 | #include <libutil.h> | |
887d5eed | 16 | #include <errno.h> |
cf37c299 A |
17 | |
18 | void | |
19 | err_mach(kern_return_t kr, const struct region *r, const char *fmt, ...) | |
20 | { | |
21 | va_list ap; | |
22 | va_start(ap, fmt); | |
23 | if (0 != kr) | |
24 | printf("%s: ", pgm); | |
25 | if (NULL != r) | |
887d5eed | 26 | printf("%016llx-%016llx ", R_ADDR(r), R_ENDADDR(r)); |
cf37c299 A |
27 | vprintf(fmt, ap); |
28 | va_end(ap); | |
29 | ||
30 | if (0 != kr) { | |
887d5eed | 31 | printf(": failed: %s (0x%x)", mach_error_string(kr), kr); |
cf37c299 A |
32 | switch (err_get_system(kr)) { |
33 | case err_get_system(err_mach_ipc): | |
34 | /* 0x10000000 == (4 << 26) */ | |
35 | printf(" => fatal\n"); | |
36 | exit(127); | |
37 | default: | |
38 | putchar('\n'); | |
39 | break; | |
40 | } | |
41 | } else | |
42 | putchar('\n'); | |
43 | } | |
44 | ||
887d5eed A |
45 | static void |
46 | vprintvr(const struct vm_range *vr, const char *restrict fmt, va_list ap) | |
47 | { | |
48 | if (NULL != vr) | |
49 | printf("%016llx-%016llx ", V_ADDR(vr), V_ENDADDR(vr)); | |
50 | vprintf(fmt, ap); | |
51 | } | |
52 | ||
53 | void | |
54 | printvr(const struct vm_range *vr, const char *fmt, ...) | |
55 | { | |
56 | va_list ap; | |
57 | va_start(ap, fmt); | |
58 | vprintvr(vr, fmt, ap); | |
59 | va_end(ap); | |
60 | } | |
61 | ||
cf37c299 A |
62 | void |
63 | printr(const struct region *r, const char *fmt, ...) | |
64 | { | |
65 | va_list ap; | |
66 | va_start(ap, fmt); | |
887d5eed | 67 | vprintvr(R_RANGE(r), fmt, ap); |
cf37c299 A |
68 | va_end(ap); |
69 | } | |
70 | ||
71 | /* | |
72 | * Print power-of-1024 sizes in human-readable form | |
73 | */ | |
74 | const char * | |
75 | str_hsize(hsize_str_t hstr, uint64_t size) | |
76 | { | |
77 | humanize_number(hstr, sizeof (hsize_str_t) - 1, size, "", | |
78 | HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL | HN_IEC_PREFIXES); | |
79 | return hstr; | |
80 | } | |
81 | ||
887d5eed A |
82 | /* |
83 | * Print VM protections in human-readable form | |
84 | */ | |
85 | const char * | |
86 | str_prot(const vm_prot_t prot) | |
87 | { | |
88 | static const char *pstr[] = { | |
89 | [0] = "---", | |
90 | [VM_PROT_READ] = "r--", | |
91 | [VM_PROT_WRITE] = "-w-", | |
92 | [VM_PROT_READ|VM_PROT_WRITE] = "rw-", | |
93 | [VM_PROT_EXECUTE] = "--x", | |
94 | [VM_PROT_READ|VM_PROT_EXECUTE] = "r-x", | |
95 | [VM_PROT_WRITE|VM_PROT_EXECUTE] = "-wx", | |
96 | [VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE] = "rwx" | |
97 | }; | |
98 | return pstr[prot & 7]; | |
99 | } | |
100 | ||
101 | // c.f. VMUVMRegion.m | |
102 | ||
103 | const char * | |
104 | str_shared(int sm) | |
105 | { | |
106 | static const char *sstr[] = { | |
107 | [0] = " ", | |
108 | [SM_COW] = "sm=cow", | |
109 | [SM_PRIVATE] = "sm=prv", | |
110 | [SM_EMPTY] = "sm=nul", | |
111 | [SM_SHARED] = "sm=ali", | |
112 | [SM_TRUESHARED] = "sm=shm", | |
113 | [SM_PRIVATE_ALIASED] = "sm=zer", | |
114 | [SM_SHARED_ALIASED] = "sm=s/a", | |
115 | [SM_LARGE_PAGE] = "sm=lpg", | |
116 | }; | |
117 | if ((unsigned)sm < sizeof (sstr) / sizeof (sstr[0])) | |
118 | return sstr[sm]; | |
119 | return "sm=???"; | |
120 | } | |
121 | ||
122 | const char * | |
123 | str_purgable(int pu, int sm) | |
124 | { | |
125 | if (SM_EMPTY == sm) | |
126 | return " "; | |
127 | static const char *pstr[] = { | |
128 | [VM_PURGABLE_NONVOLATILE] = "p=n", | |
129 | [VM_PURGABLE_VOLATILE] = "p=v", | |
130 | [VM_PURGABLE_EMPTY] = "p=e", | |
131 | [VM_PURGABLE_DENY] = " ", | |
132 | }; | |
133 | if ((unsigned)pu < sizeof (pstr) / sizeof (pstr[0])) | |
134 | return pstr[pu]; | |
135 | return "p=?"; | |
136 | } | |
137 | ||
138 | /* | |
139 | * c.f. VMURegionTypeDescriptionForTagShareProtAndPager. | |
140 | */ | |
141 | const char * | |
142 | str_tag(tag_str_t tstr, int tag, int share_mode, vm_prot_t curprot, int external_pager) | |
143 | { | |
144 | const char *rtype; | |
145 | ||
146 | switch (tag) { | |
147 | case 0: | |
148 | if (external_pager) | |
149 | rtype = "mapped file"; | |
150 | else if (SM_TRUESHARED == share_mode) | |
151 | rtype = "shared memory"; | |
152 | else | |
153 | rtype = "VM_allocate"; | |
154 | break; | |
155 | case VM_MEMORY_MALLOC: | |
156 | if (VM_PROT_NONE == curprot) | |
157 | rtype = "MALLOC guard page"; | |
158 | else if (SM_EMPTY == share_mode) | |
159 | rtype = "MALLOC"; | |
160 | else | |
161 | rtype = "MALLOC metadata"; | |
162 | break; | |
163 | case VM_MEMORY_STACK: | |
164 | if (VM_PROT_NONE == curprot) | |
165 | rtype = "Stack guard"; | |
166 | else | |
167 | rtype = "Stack"; | |
168 | break; | |
169 | #if defined(CONFIG_DEBUG) || defined(CONFIG_GCORE_MAP) | |
170 | case VM_MEMORY_MALLOC_SMALL: | |
171 | rtype = "MALLOC_SMALL"; | |
172 | break; | |
173 | case VM_MEMORY_MALLOC_LARGE: | |
174 | rtype = "MALLOC_LARGE"; | |
175 | break; | |
176 | case VM_MEMORY_MALLOC_HUGE: | |
177 | rtype = "MALLOC_HUGE"; | |
178 | break; | |
179 | case VM_MEMORY_SBRK: | |
180 | rtype = "SBRK"; | |
181 | break; | |
182 | case VM_MEMORY_REALLOC: | |
183 | rtype = "MALLOC_REALLOC"; | |
184 | break; | |
185 | case VM_MEMORY_MALLOC_TINY: | |
186 | rtype = "MALLOC_TINY"; | |
187 | break; | |
188 | case VM_MEMORY_MALLOC_LARGE_REUSABLE: | |
189 | rtype = "MALLOC_LARGE_REUSABLE"; | |
190 | break; | |
191 | case VM_MEMORY_MALLOC_LARGE_REUSED: | |
192 | rtype = "MALLOC_LARGE"; | |
193 | break; | |
194 | case VM_MEMORY_ANALYSIS_TOOL: | |
195 | rtype = "Performance tool data"; | |
196 | break; | |
197 | case VM_MEMORY_MALLOC_NANO: | |
198 | rtype = "MALLOC_NANO"; | |
199 | break; | |
200 | case VM_MEMORY_MACH_MSG: | |
201 | rtype = "Mach message"; | |
202 | break; | |
203 | case VM_MEMORY_IOKIT: | |
204 | rtype = "IOKit"; | |
205 | break; | |
206 | case VM_MEMORY_GUARD: | |
207 | rtype = "Guard"; | |
208 | break; | |
209 | case VM_MEMORY_SHARED_PMAP: | |
210 | rtype = "shared pmap"; | |
211 | break; | |
212 | case VM_MEMORY_DYLIB: | |
213 | rtype = "dylib"; | |
214 | break; | |
215 | case VM_MEMORY_OBJC_DISPATCHERS: | |
216 | rtype = "ObjC dispatching code"; | |
217 | break; | |
218 | case VM_MEMORY_UNSHARED_PMAP: | |
219 | rtype = "unshared pmap"; | |
220 | break; | |
221 | case VM_MEMORY_APPKIT: | |
222 | rtype = "AppKit"; | |
223 | break; | |
224 | case VM_MEMORY_FOUNDATION: | |
225 | rtype = "Foundation"; | |
226 | break; | |
227 | case VM_MEMORY_COREGRAPHICS: | |
228 | rtype = "CoreGraphics"; | |
229 | break; | |
230 | case VM_MEMORY_CORESERVICES: | |
231 | rtype = "CoreServices"; | |
232 | break; | |
233 | case VM_MEMORY_JAVA: | |
234 | rtype = "Java"; | |
235 | break; | |
236 | case VM_MEMORY_COREDATA: | |
237 | rtype = "CoreData"; | |
238 | break; | |
239 | case VM_MEMORY_COREDATA_OBJECTIDS: | |
240 | rtype = "CoreData Object IDs"; | |
241 | break; | |
242 | case VM_MEMORY_ATS: | |
243 | rtype = "ATS (font support)"; | |
244 | break; | |
245 | case VM_MEMORY_LAYERKIT: | |
246 | rtype = "CoreAnimation"; | |
247 | break; | |
248 | case VM_MEMORY_CGIMAGE: | |
249 | rtype = "CG image"; | |
250 | break; | |
251 | case VM_MEMORY_TCMALLOC: | |
252 | rtype = "WebKit Malloc"; | |
253 | break; | |
254 | case VM_MEMORY_COREGRAPHICS_DATA: | |
255 | rtype = "CG raster data"; | |
256 | break; | |
257 | case VM_MEMORY_COREGRAPHICS_SHARED: | |
258 | rtype = "CG shared images"; | |
259 | break; | |
260 | case VM_MEMORY_COREGRAPHICS_FRAMEBUFFERS: | |
261 | rtype = "CG framebuffers"; | |
262 | break; | |
263 | case VM_MEMORY_COREGRAPHICS_BACKINGSTORES: | |
264 | rtype = "CG backingstores"; | |
265 | break; | |
266 | case VM_MEMORY_DYLD: | |
267 | rtype = "dyld private memory"; | |
268 | break; | |
269 | case VM_MEMORY_DYLD_MALLOC: | |
270 | rtype = "dyld malloc memory"; | |
271 | break; | |
272 | case VM_MEMORY_SQLITE: | |
273 | rtype = "SQlite page cache"; | |
274 | break; | |
275 | case VM_MEMORY_JAVASCRIPT_CORE: | |
276 | rtype = "WebAssembly memory"; | |
277 | break; | |
278 | case VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR: | |
279 | rtype = "JS JIT generated code"; | |
280 | break; | |
281 | case VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE: | |
282 | rtype = "JS VM register file"; | |
283 | break; | |
284 | case VM_MEMORY_GLSL: | |
285 | rtype = "OpenGL GLSL"; | |
286 | break; | |
287 | case VM_MEMORY_OPENCL: | |
288 | rtype = "OpenCL"; | |
289 | break; | |
290 | case VM_MEMORY_COREIMAGE: | |
291 | rtype = "CoreImage"; | |
292 | break; | |
293 | case VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS: | |
294 | rtype = "WebCore purgable data"; | |
295 | break; | |
296 | case VM_MEMORY_IMAGEIO: | |
297 | rtype = "Image IO"; | |
298 | break; | |
299 | case VM_MEMORY_COREPROFILE: | |
300 | rtype = "CoreProfile"; | |
301 | break; | |
302 | case VM_MEMORY_ASSETSD: | |
303 | rtype = "Assets Library"; | |
304 | break; | |
305 | case VM_MEMORY_OS_ALLOC_ONCE: | |
306 | rtype = "OS Alloc Once"; | |
307 | break; | |
308 | case VM_MEMORY_LIBDISPATCH: | |
309 | rtype = "Dispatch continuations"; | |
310 | break; | |
311 | case VM_MEMORY_ACCELERATE: | |
312 | rtype = "Accelerate framework"; | |
313 | break; | |
314 | case VM_MEMORY_COREUI: | |
315 | rtype = "CoreUI image data"; | |
316 | break; | |
317 | case VM_MEMORY_COREUIFILE: | |
318 | rtype = "CoreUI image file"; | |
319 | break; | |
320 | case VM_MEMORY_GENEALOGY: | |
321 | rtype = "Activity Tracing"; | |
322 | break; | |
323 | case VM_MEMORY_RAWCAMERA: | |
324 | rtype = "RawCamera"; | |
325 | break; | |
326 | case VM_MEMORY_CORPSEINFO: | |
327 | rtype = "Process Corpse Info"; | |
328 | break; | |
329 | case VM_MEMORY_ASL: | |
330 | rtype = "Apple System Log"; | |
331 | break; | |
332 | case VM_MEMORY_SWIFT_RUNTIME: | |
333 | rtype = "Swift runtime"; | |
334 | break; | |
335 | case VM_MEMORY_SWIFT_METADATA: | |
336 | rtype = "Swift metadata"; | |
337 | break; | |
338 | case VM_MEMORY_DHMM: | |
339 | rtype = "DHMM"; | |
340 | break; | |
341 | case VM_MEMORY_SCENEKIT: | |
342 | rtype = "SceneKit"; | |
343 | break; | |
344 | case VM_MEMORY_SKYWALK: | |
345 | rtype = "Skywalk Networking"; | |
346 | break; | |
347 | #endif | |
348 | default: | |
349 | rtype = NULL; | |
350 | break; | |
351 | } | |
352 | if (rtype) | |
353 | snprintf(tstr, sizeof (tag_str_t), "%s", rtype); | |
354 | else | |
355 | snprintf(tstr, sizeof (tag_str_t), "tag #%d", tag); | |
356 | return tstr; | |
357 | } | |
358 | ||
359 | const char * | |
360 | str_tagr(tag_str_t tstr, const struct region *r) { | |
361 | return str_tag(tstr, r->r_info.user_tag, r->r_info.share_mode, r->r_info.protection, r->r_info.external_pager); | |
362 | } | |
363 | ||
cf37c299 A |
364 | /* |
365 | * Put two strings together separated by a '+' sign | |
887d5eed | 366 | * If the string gets too long, then add an ellipsis and |
cf37c299 A |
367 | * stop concatenating it. |
368 | */ | |
369 | char * | |
370 | strconcat(const char *s0, const char *s1, size_t maxlen) | |
371 | { | |
372 | const char ellipsis[] = "..."; | |
373 | const char junction[] = ", "; | |
374 | const size_t s0len = strlen(s0); | |
375 | size_t nmlen = s0len + strlen(s1) + strlen(junction) + 1; | |
376 | if (maxlen > strlen(ellipsis) && nmlen > maxlen) { | |
377 | if (strcmp(s0 + s0len - strlen(ellipsis), ellipsis) == 0) | |
378 | return strdup(s0); | |
379 | s1 = ellipsis; | |
380 | nmlen = s0len + strlen(s1) + strlen(junction) + 1; | |
381 | } | |
382 | char *p = malloc(nmlen); | |
383 | if (p) { | |
384 | strlcpy(p, s0, nmlen); | |
385 | strlcat(p, junction, nmlen); | |
386 | strlcat(p, s1, nmlen); | |
387 | } | |
388 | return p; | |
389 | } | |
887d5eed A |
390 | |
391 | unsigned long | |
392 | simple_namehash(const char *nm) | |
393 | { | |
394 | unsigned long result = 5381; | |
395 | int c; | |
396 | while (0 != (c = *nm++)) | |
397 | result = (result * 33) ^ c; | |
398 | return result; /* modified djb2 */ | |
399 | } | |
400 | ||
401 | int | |
402 | bounded_pwrite(int fd, const void *addr, size_t size, off_t off, bool *nocache, ssize_t *nwrittenp) | |
403 | { | |
404 | if (opt->sizebound && off + (off_t)size > opt->sizebound) | |
405 | return EFBIG; | |
406 | ||
407 | bool oldnocache = *nocache; | |
408 | if (size >= opt->ncthresh && !oldnocache) | |
409 | *nocache = 0 == fcntl(fd, F_NOCACHE, 1); | |
410 | else if (size < opt->ncthresh && oldnocache) | |
411 | *nocache = 0 != fcntl(fd, F_NOCACHE, 0); | |
412 | if (OPTIONS_DEBUG(opt, 3) && oldnocache ^ *nocache) | |
413 | printf("F_NOCACHE now %sabled on fd %d\n", *nocache ? "en" : "dis", fd); | |
414 | ||
415 | const ssize_t nwritten = pwrite(fd, addr, size, off); | |
416 | if (-1 == nwritten) | |
417 | return errno; | |
418 | if (nwrittenp) | |
419 | *nwrittenp = nwritten; | |
420 | return 0; | |
421 | } |