| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <inttypes.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <zircon/status.h> |
| #include <zircon/syscalls.h> |
| #include <zircon/syscalls/object.h> |
| |
| #include <pretty/sizes.h> |
| #include <task-utils/get.h> |
| |
| #include "vmo-utils.h" |
| |
| static constexpr size_t kRightsStrLen = sizeof("rwxmdt"); |
| |
| static const char* handle_rights_to_string(uint32_t rights, char str[kRightsStrLen]) { |
| char* c = str; |
| *c++ = (rights & ZX_RIGHT_READ) ? 'r' : '-'; |
| *c++ = (rights & ZX_RIGHT_WRITE) ? 'w' : '-'; |
| *c++ = (rights & ZX_RIGHT_EXECUTE) ? 'x' : '-'; |
| *c++ = (rights & ZX_RIGHT_MAP) ? 'm' : '-'; |
| *c++ = (rights & ZX_RIGHT_DUPLICATE) ? 'd' : '-'; |
| *c++ = (rights & ZX_RIGHT_TRANSFER) ? 't' : '-'; |
| *c = '\0'; |
| return str; |
| } |
| |
| static void print_vmo(const zx_info_vmo_t* vmo) { |
| char rights_str[kRightsStrLen]; |
| if (vmo->flags & ZX_INFO_VMO_VIA_HANDLE) { |
| handle_rights_to_string(vmo->handle_rights, rights_str); |
| } else { |
| rights_str[0] = '-'; |
| rights_str[1] = '\0'; |
| } |
| |
| char size_str[MAX_FORMAT_SIZE_LEN]; |
| format_size(size_str, sizeof(size_str), vmo->size_bytes); |
| |
| char alloc_str[MAX_FORMAT_SIZE_LEN]; |
| switch (ZX_INFO_VMO_TYPE(vmo->flags)) { |
| case ZX_INFO_VMO_TYPE_PAGED: |
| format_size(alloc_str, sizeof(alloc_str), vmo->committed_bytes); |
| break; |
| case ZX_INFO_VMO_TYPE_PHYSICAL: |
| strlcpy(alloc_str, "phys", sizeof(alloc_str)); |
| break; |
| default: |
| // Unexpected: all VMOs should be one of the above types. |
| snprintf(alloc_str, sizeof(alloc_str), "?0x%" PRIx32 "?", vmo->flags); |
| break; |
| } |
| |
| char parent_str[21]; |
| if (vmo->flags & ZX_INFO_VMO_IS_COW_CLONE) { |
| snprintf(parent_str, sizeof(parent_str), "%" PRIu64, vmo->parent_koid); |
| } else { |
| parent_str[0] = '-'; |
| parent_str[1] = '\0'; |
| } |
| |
| char name[ZX_MAX_NAME_LEN]; |
| strlcpy(name, vmo->name, sizeof(name)); |
| if (name[0] == '\0') { |
| name[0] = '-'; |
| name[1] = '\0'; |
| } |
| |
| printf( |
| "%6s " // rights |
| "%5" PRIu64 |
| " " // koid |
| "%6s " // parent koid |
| "%5zu " // number of children |
| "%4zu " // map count |
| "%4zu " // share count |
| "%7s " // size in bytes |
| "%7s " // allocated bytes |
| "%s\n", // name |
| rights_str, vmo->koid, parent_str, vmo->num_children, vmo->num_mappings, vmo->share_count, |
| size_str, alloc_str, name); |
| } |
| |
| static void print_header() { printf("rights koid parent #chld #map #shr size alloc name\n"); } |
| |
| // Pretty-prints the contents of |vmos| to stdout. |
| void print_vmos(const zx_info_vmo_t* vmos, size_t count, size_t avail) { |
| print_header(); |
| for (size_t i = 0; i < count; i++) { |
| print_vmo(vmos + i); |
| } |
| if (avail > count) { |
| printf("[%zd entries truncated]\n", avail - count); |
| } |
| print_header(); |
| } |
| |
| void try_help(char** argv) { |
| const char* c = argv[1]; |
| while (*c == '-') { |
| c++; |
| } |
| if (strcmp(c, "help") != 0) { |
| return; |
| } |
| |
| printf("Usage: %s <process-koid>\n", argv[0]); |
| printf("\n"); |
| printf("Dumps a process's VMOs to stdout.\n"); |
| printf("\n"); |
| printf("The process either maps or has a handle to every VMO in this list (or both).\n"); |
| printf("The same VMO may appear multiple times: the process could map the same VMO\n"); |
| printf("twice, or have two handles to it, or both map it and have a handle to it.\n"); |
| // TODO(dbort): Consider de-duping the entries. |
| printf("\n"); |
| printf("Columns:\n"); |
| printf(" rights: If the process points to the VMO via a handle, this column\n"); |
| printf(" shows the rights that the handle has, zero or more of:\n"); |
| printf(" r: ZX_RIGHT_READ\n"); |
| printf(" w: ZX_RIGHT_WRITE\n"); |
| printf(" x: ZX_RIGHT_EXECUTE\n"); |
| printf(" m: ZX_RIGHT_MAP\n"); |
| printf(" d: ZX_RIGHT_DUPLICATE\n"); |
| printf(" t: ZX_RIGHT_TRANSFER\n"); |
| printf(" NOTE: Non-handle entries will have a single '-' in this column.\n"); |
| printf(" koid: The koid of the VMO, if it has one. Zero otherwise. A VMO without a\n"); |
| printf(" koid was created by the kernel, and has never had a userspace handle.\n"); |
| printf(" parent: The koid of the VMO's parent, if it's a clone.\n"); |
| printf(" #chld: The number of active clones (children) of the VMO.\n"); |
| printf(" #map: The number of times the VMO is currently mapped into VMARs.\n"); |
| printf(" #shr: The number of processes that map (share) the VMO.\n"); |
| printf(" size: The VMO's current size, in bytes.\n"); |
| printf(" alloc: The amount of physical memory allocated to the VMO, in bytes.\n"); |
| printf(" NOTE: If this column contains the value 'phys', it means that the\n"); |
| printf(" VMO points to a raw physical address range like a memory-mapped\n"); |
| printf(" device. 'phys' VMOs do not consume RAM.\n"); |
| printf(" name: The name of the VMO, or - if its name is empty.\n"); |
| exit(0); |
| } |
| |
| __NO_RETURN void usage(const char* argv0) { |
| fprintf(stderr, "Usage: %s <process-koid>|help\n", argv0); |
| exit(1); |
| } |
| |
| int main(int argc, char** argv) { |
| if (argc != 2) { |
| usage(argv[0]); |
| } |
| try_help(argv); |
| char* end; |
| zx_koid_t koid = strtoull(argv[1], &end, 0); |
| if (argv[1][0] == '\0' || *end != '\0') { |
| fprintf(stderr, "ERROR: \"%s\" is not a number\n", argv[1]); |
| usage(argv[0]); |
| } |
| |
| zx_handle_t process; |
| zx_obj_type_t type; |
| zx_status_t s = get_task_by_koid(koid, &type, &process); |
| if (s == ZX_OK && type != ZX_OBJ_TYPE_PROCESS) { |
| zx_handle_close(process); |
| s = ZX_ERR_WRONG_TYPE; |
| } |
| if (s != ZX_OK) { |
| fprintf(stderr, "ERROR: couldn't find process with koid %" PRIu64 ": %s (%d)\n", koid, |
| zx_status_get_string(s), s); |
| usage(argv[0]); |
| } |
| |
| zx_info_vmo_t* vmos; |
| size_t count; |
| size_t avail; |
| s = get_vmos(process, &vmos, &count, &avail); |
| zx_handle_close(process); |
| if (s != ZX_OK) { |
| fprintf(stderr, "ERROR: couldn't get vmos for process with koid %" PRIu64 ": %s (%d)\n", koid, |
| zx_status_get_string(s), s); |
| return 1; |
| } |
| print_vmos(vmos, count, avail); |
| free(vmos); |
| return 0; |
| } |