Skip to content

Instantly share code, notes, and snippets.

@kostikbel
Last active September 17, 2021 08:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kostikbel/1f0de166c34d822b6aa7a05110ede8be to your computer and use it in GitHub Desktop.
Save kostikbel/1f0de166c34d822b6aa7a05110ede8be to your computer and use it in GitHub Desktop.
/* $Id: shadow_show.c,v 1.4 2021/05/04 14:55:03 kostik Exp kostik $ */
/* /usr/local/opt/gcc-11.1.0/bin/gcc -Wall -Wextra -g -O -o shadow_show shadow_show.c -lutil */
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <err.h>
#include <libutil.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static struct swinfo {
struct kinfo_vmobject sw_vmo;
pid_t sw_pid;
} *swobj;
static int nswobj;
static int
swobj_search(const void *a, const void *b)
{
const uint64_t *aa = a;
const struct swinfo *bb = b;
if (*aa == bb->sw_vmo.kvo_me)
return (0);
return (*aa > bb->sw_vmo.kvo_me ? -1 : 1);
}
static int
swobj_sort(const void *a, const void *b)
{
return (((const struct swinfo *)a)->sw_vmo.kvo_me >
((const struct swinfo *)b)->sw_vmo.kvo_me ? -1 : 1);
}
static bool
get_swap_vmobjects(void)
{
struct kinfo_vmobject *kvo;
struct swinfo *swi;
int cnt, i, next_i, last_nswobj, max;
max = next_i = nswobj = 0;
kvo = kinfo_getvmobject(&cnt);
if (kvo == NULL) {
err(1, "kinfo_getvmobject()");
return (false);
}
do {
for (i = next_i; i < cnt; i++) {
if (kvo[i].kvo_type != KVME_TYPE_DEFAULT &&
kvo[i].kvo_type != KVME_TYPE_SWAP)
continue;
if (nswobj < max) {
swi = &swobj[nswobj];
memcpy(&swi->sw_vmo, &kvo[i],
sizeof(struct kinfo_vmobject));
swi->sw_pid = 0;
next_i = i + 1;
}
nswobj++;
}
if (nswobj <= max)
break;
/* allocate memory and fill skipped elements */
last_nswobj = max;
max = nswobj;
nswobj = last_nswobj;
/* allocate more memory and fill missed ones */
swobj = realloc(swobj, max * sizeof(struct swinfo));
if (swobj == NULL)
err(1, "Out of memory");
} while (i <= cnt); /* extra safety guard */
free(kvo);
if (nswobj > 1)
qsort(swobj, nswobj, sizeof (swobj[0]), swobj_sort);
return (nswobj > 0);
}
static void
handle_proc(pid_t pid)
{
struct kinfo_vmentry *kvm, *kve;
struct swinfo *swi;
uint64_t vmobj_handle;
uint64_t resident_pages, swapped_pages;
int cnt, i, j, tab_level;
kvm = kinfo_getvmmap(pid, &cnt);
if (kvm == NULL) {
warnx("Cannot get vm map for pid %d", pid);
return;
}
printf("pid %d\n", pid);
resident_pages = swapped_pages = 0;
for (i = 0; i < cnt; i++) {
kve = &kvm[i];
if (kve->kve_type != KVME_TYPE_DEFAULT &&
kve->kve_type != KVME_TYPE_SWAP)
continue;
printf("%#019jx-%#019jx\n", (uintmax_t)kve->kve_start,
(uintmax_t)kve->kve_end);
vmobj_handle = kve->kve_obj;
for (tab_level = 1;; tab_level += 1) {
if (vmobj_handle == 0)
break;
for (j = 0; j < tab_level; j++)
printf(" ");
printf("%#019jx ", vmobj_handle);
swi = bsearch(&vmobj_handle, swobj, nswobj,
sizeof(swobj[0]), swobj_search);
if (swi == NULL) {
printf("\n");
break;
}
printf("%ju %ju\n", (uintmax_t)swi->sw_vmo.kvo_resident,
(uintmax_t)swi->sw_vmo.kvo_swapped);
if (swi->sw_pid != pid) {
resident_pages += swi->sw_vmo.kvo_resident;
swapped_pages += swi->sw_vmo.kvo_swapped;
swi->sw_pid = pid;
}
vmobj_handle = swi->sw_vmo.kvo_backing_obj;
}
}
printf("Total %ju %ju\n", (uintmax_t)resident_pages,
(uintmax_t)swapped_pages);
}
int
main(int argc, char *argv[])
{
pid_t pid;
int i;
if (!get_swap_vmobjects())
exit(1);
for (i = 1; i < argc; i++) {
pid = atoi(argv[i]);
handle_proc(pid);
}
exit(0);
}
/* $Id: shadow_show.c,v 1.3 2021/05/04 14:20:58 kostik Exp kostik $ */
/* /usr/local/opt/gcc-11.1.0/bin/gcc -Wall -Wextra -g -O -o shadow_show shadow_show.c -lutil */
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <err.h>
#include <libutil.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
static struct swapvm {
uint64_t kvo_me;
uint32_t swapped_pages;
uint64_t next;
} *swobj = NULL;
static int nswobj = 0;
static int
swobj_search(const void *a, const void *b)
{
const uint64_t *aa = a;
const struct swapvm *bb = b;
if (*aa == bb->kvo_me)
return (0);
return (*aa > bb->kvo_me ? -1 : 1);
}
static int
swobj_sort(const void *a, const void *b)
{
return (((const struct swapvm *)a)->kvo_me >
((const struct swapvm *)b)->kvo_me ? -1: 1);
}
static bool
get_swap_vmobjects(void)
{
struct kinfo_vmobject *kvo;
int cnt, i, next_i, last_nswobj, max;
max = next_i = nswobj = 0;
kvo = kinfo_getvmobject(&cnt);
if (kvo == NULL) {
err(1, "kinfo_getvmobject()");
return (false);
}
do {
for (i = next_i; i < cnt; i++) {
if (kvo[i].kvo_type != KVME_TYPE_DEFAULT &&
kvo[i].kvo_type != KVME_TYPE_SWAP)
continue;
if (nswobj < max) {
swobj[nswobj].kvo_me = kvo[i].kvo_me;
swobj[nswobj].swapped_pages =
kvo[i].kvo_swapped;
swobj[nswobj].next = kvo[i].kvo_backing_obj;
next_i = i + 1;
}
nswobj++;
}
if (nswobj <= max)
break;
/* allocate memory and fill skipped elements */
last_nswobj = max;
max = nswobj;
nswobj = last_nswobj;
/* allocate more memory and fill missed ones */
if ((swobj = realloc(swobj, max * sizeof(*swobj))) == NULL)
err(1, "Out of memory");
} while (i <= cnt); /* extra safety guard */
free(kvo);
if (nswobj > 1)
qsort(swobj, nswobj, sizeof (swobj[0]), swobj_sort);
return (nswobj > 0);
}
static void
handle_proc(pid_t pid)
{
struct kinfo_vmentry *kvm, *kve;
struct swapvm *svm;
uint64_t vmobj_handle;
uint64_t swapped_pages;
int cnt, i, j, tab_level;
kvm = kinfo_getvmmap(pid, &cnt);
if (kvm == NULL) {
warnx("Cannot get vm map for pid %d", pid);
return;
}
printf("pid %d\n", pid);
swapped_pages = 0;
for (i = 0; i < cnt; i++) {
kve = &kvm[i];
if (kve->kve_type != KVME_TYPE_DEFAULT &&
kve->kve_type != KVME_TYPE_SWAP)
continue;
printf("%#019jx-%#019jx\n", (uintmax_t)kve->kve_start,
(uintmax_t)kve->kve_end);
vmobj_handle = kve->kve_obj;
for (tab_level = 1;; tab_level += 1) {
if (vmobj_handle == 0)
break;
for (j = 0; j < tab_level; j++)
printf(" ");
printf("%#019jx ", vmobj_handle);
svm = bsearch(&vmobj_handle, swobj, nswobj,
sizeof(swobj[0]), swobj_search);
if (svm == NULL) {
printf("\n");
break;
}
printf("%ju\n", (uintmax_t)svm->swapped_pages);
swapped_pages += svm->swapped_pages;
vmobj_handle = svm->next;
}
}
printf("Total %ju\n", swapped_pages);
}
int
main(int argc, char *argv[])
{
pid_t pid;
int i;
if (!get_swap_vmobjects())
exit(1);
for (i = 1; i < argc; i++) {
pid = atoi(argv[i]);
handle_proc(pid);
}
exit(0);
}
@coder03
Copy link

coder03 commented Sep 14, 2021

This code looks awesome, I am trying to compile this in freebsd 13 and getting this error:

**[freebsd13.0]# /usr/local/opt/bin/gcc -Wall -Wextra -g -O -o shadow_show shadow_show.c -lutil
shadow_show.c: In function âget_swap_vmobjectsâ:
shadow_show.c:57:63: error: âstruct kinfo_vmobjectâ has no member named âkvo_meâ; did you mean âkvo_typeâ?
57 | swobj[nswobj].kvo_me = kvo[i].kvo_me;
| ^~~~~~
| kvo_type
shadow_show.c:59:43: error: âstruct kinfo_vmobjectâ has no member named âkvo_swappedâ
59 | kvo[i].kvo_swapped;
| ^
shadow_show.c:60:60: error: âstruct kinfo_vmobjectâ has no member named âkvo_backing_objâ
60 | swobj[nswobj].next = kvo[i].kvo_backing_obj;
| ^
shadow_show.c: In function âhandle_procâ:
shadow_show.c:104:35: error: âstruct kinfo_vmentryâ has no member named âkve_objâ
104 | vmobj_handle = kve->kve_obj;
| ^~
[freebsd13.0]#/usr/local/opt/bin/gcc --version
gcc (GCC) 11.1.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

[freebsd13.0]#**

Could you please help fix this compilation issue.

@kostikbel
Copy link
Author

This feature requires stable/13 or HEAD. I suspect you use 13.0 release.

@coder03
Copy link

coder03 commented Sep 17, 2021

Yes, I am using 13.0 release. Thank you for your time, I will try stable/13 or HEAD :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment