| /* |
| * pmap implementation for busybox |
| * |
| * Copyright (C) 2010 Nokia Corporation. All rights reserved. |
| * Written by Alexander Shishkin <virtuoso@slind.org> |
| * |
| * Licensed under GPLv2 or later, see the LICENSE file in this source tree |
| * for details. |
| */ |
| |
| //config:config PMAP |
| //config: bool "pmap" |
| //config: default y |
| //config: help |
| //config: Display processes' memory mappings. |
| |
| //applet:IF_PMAP(APPLET(pmap, BB_DIR_USR_BIN, BB_SUID_DROP)) |
| //kbuild:lib-$(CONFIG_PMAP) += pmap.o |
| |
| //usage:#define pmap_trivial_usage |
| //usage: "[-xq] PID" |
| //usage:#define pmap_full_usage "\n\n" |
| //usage: "Display detailed process memory usage" |
| //usage: "\n" |
| //usage: "\n -x Show details" |
| //usage: "\n -q Quiet" |
| |
| #include "libbb.h" |
| |
| #if ULONG_MAX == 0xffffffff |
| # define TABS "\t" |
| # define AFMT "8" |
| # define DASHES "" |
| #else |
| # define TABS "\t\t" |
| # define AFMT "16" |
| # define DASHES "--------" |
| #endif |
| |
| enum { |
| OPT_x = 1 << 0, |
| OPT_q = 1 << 1, |
| }; |
| |
| static void print_smaprec(struct smaprec *currec, void *data) |
| { |
| unsigned opt = (uintptr_t)data; |
| |
| printf("%0" AFMT "lx ", currec->smap_start); |
| |
| if (opt & OPT_x) |
| printf("%7lu %7lu %7lu %7lu ", |
| currec->smap_size, |
| currec->smap_pss, |
| currec->private_dirty, |
| currec->smap_swap); |
| else |
| printf("%7luK", currec->smap_size); |
| |
| printf(" %.4s %s\n", currec->smap_mode, currec->smap_name); |
| } |
| |
| static int procps_get_maps(pid_t pid, unsigned opt) |
| { |
| struct smaprec total; |
| int ret; |
| char buf[256]; |
| |
| read_cmdline(buf, sizeof(buf), pid, "no such process"); |
| printf("%u: %s\n", (int)pid, buf); |
| |
| if (!(opt & OPT_q) && (opt & OPT_x)) |
| puts("Address" TABS " Kbytes PSS Dirty Swap Mode Mapping"); |
| |
| memset(&total, 0, sizeof(total)); |
| |
| ret = procps_read_smaps(pid, &total, print_smaprec, (void*)(uintptr_t)opt); |
| if (ret) |
| return ret; |
| |
| if (!(opt & OPT_q)) { |
| if (opt & OPT_x) |
| printf("--------" DASHES " ------ ------ ------ ------\n" |
| "total" TABS " %7lu %7lu %7lu %7lu\n", |
| total.smap_size, total.smap_pss, total.private_dirty, total.smap_swap); |
| else |
| printf("mapped: %luK\n", total.smap_size); |
| } |
| |
| return 0; |
| } |
| |
| int pmap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| int pmap_main(int argc UNUSED_PARAM, char **argv) |
| { |
| unsigned opts; |
| int ret; |
| |
| opts = getopt32(argv, "xq"); |
| argv += optind; |
| |
| ret = 0; |
| while (*argv) { |
| pid_t pid = xatoi_positive(*argv++); |
| /* GNU pmap returns 42 if any of the pids failed */ |
| if (procps_get_maps(pid, opts) != 0) |
| ret = 42; |
| } |
| |
| return ret; |
| } |