Blame sysdeps/darwin/procmem.c

Packit d37888
/*
Packit d37888
   This file is part of LibGTop 2.0.
Packit d37888
Packit d37888
   LibGTop is free software; you can redistribute it and/or modify it
Packit d37888
   under the terms of the GNU General Public License as published by
Packit d37888
   the Free Software Foundation; either version 2 of the License,
Packit d37888
   or (at your option) any later version.
Packit d37888
Packit d37888
   LibGTop is distributed in the hope that it will be useful, but WITHOUT
Packit d37888
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
Packit d37888
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit d37888
   for more details.
Packit d37888
Packit d37888
   You should have received a copy of the GNU General Public License
Packit d37888
   along with LibGTop; see the file COPYING. If not, write to the
Packit d37888
   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Packit d37888
   Boston, MA 02110-1301, USA.
Packit d37888
*/
Packit d37888
Packit d37888
#include <config.h>
Packit d37888
#include <unistd.h>
Packit d37888
Packit d37888
#include <glibtop.h>
Packit d37888
#include <glibtop/error.h>
Packit d37888
#include <glibtop/procmem.h>
Packit d37888
Packit d37888
#include <glibtop_suid.h>
Packit d37888
Packit d37888
#include <mach/mach_init.h>
Packit d37888
#include <mach/mach_host.h>
Packit d37888
#include <mach/mach_traps.h>
Packit d37888
#include <mach/task.h>
Packit d37888
#include <mach/vm_map.h>
Packit d37888
#include <mach/shared_memory_server.h>
Packit d37888
Packit d37888
static const unsigned long _glibtop_sysdeps_proc_mem =
Packit d37888
(1L << GLIBTOP_PROC_MEM_SIZE)     + (1L << GLIBTOP_PROC_MEM_VSIZE) +
Packit d37888
(1L << GLIBTOP_PROC_MEM_RESIDENT) + (1L << GLIBTOP_PROC_MEM_SHARE) +
Packit d37888
(1L << GLIBTOP_PROC_MEM_RSS);
Packit d37888
Packit d37888
/* Init function. */
Packit d37888
Packit d37888
void
Packit d37888
_glibtop_init_proc_mem_p (glibtop *server)
Packit d37888
{
Packit d37888
	server->sysdeps.proc_mem = _glibtop_sysdeps_proc_mem;
Packit d37888
}
Packit d37888
Packit d37888
Packit d37888
#define	SHARED_TABLE_SIZE	137
Packit d37888
#define	TEXT_SEGMENT_START	(GLOBAL_SHARED_TEXT_SEGMENT)
Packit d37888
#define TEXT_SEGMENT_END	(GLOBAL_SHARED_TEXT_SEGMENT + SHARED_TEXT_REGION_SIZE)
Packit d37888
#define	DATA_SEGMENT_START	(GLOBAL_SHARED_DATA_SEGMENT)
Packit d37888
#define DATA_SEGMENT_END	(GLOBAL_SHARED_DATA_SEGMENT + SHARED_DATA_REGION_SIZE)
Packit d37888
Packit d37888
struct shared_info {
Packit d37888
	unsigned obj_id;
Packit d37888
	unsigned share_mode;
Packit d37888
	unsigned page_count;
Packit d37888
	unsigned ref_count;
Packit d37888
	unsigned task_ref_count;
Packit d37888
	vm_size_t size;
Packit d37888
	struct shared_info *next;
Packit d37888
};
Packit d37888
typedef struct shared_info shared_table[SHARED_TABLE_SIZE];
Packit d37888
typedef struct shared_info shared_info;
Packit d37888
Packit d37888
static void
Packit d37888
shared_table_init (shared_table table)
Packit d37888
{
Packit d37888
	memset (table, 0, sizeof (shared_table));
Packit d37888
}
Packit d37888
Packit d37888
static void
Packit d37888
shared_table_free (glibtop *server, shared_table table)
Packit d37888
{
Packit d37888
	int i;
Packit d37888
Packit d37888
	for (i = 0; i < SHARED_TABLE_SIZE; i++) {
Packit d37888
		shared_info *info = table [i].next;
Packit d37888
Packit d37888
		while (info) {
Packit d37888
			shared_info *next = info->next;
Packit d37888
			g_free (info);
Packit d37888
			info = next;
Packit d37888
		}
Packit d37888
	}
Packit d37888
}
Packit d37888
Packit d37888
static void
Packit d37888
shared_table_register (glibtop *server, shared_table table,
Packit d37888
		       vm_region_top_info_data_t *top, vm_size_t size)
Packit d37888
{
Packit d37888
	shared_info *info, *last;
Packit d37888
Packit d37888
	info = last = &table [top->obj_id % SHARED_TABLE_SIZE];
Packit d37888
	while (info) {
Packit d37888
		if (info->obj_id == top->obj_id) {
Packit d37888
			info->task_ref_count++;
Packit d37888
			return;
Packit d37888
		}
Packit d37888
		last = info;
Packit d37888
		info = info->next;
Packit d37888
	}
Packit d37888
Packit d37888
	info = g_malloc (sizeof (shared_info));
Packit d37888
	if (info) {
Packit d37888
		info->obj_id = top->obj_id;
Packit d37888
		info->share_mode = top->share_mode;
Packit d37888
		info->page_count = top->shared_pages_resident;
Packit d37888
		info->ref_count = top->ref_count;
Packit d37888
		info->task_ref_count = 1;
Packit d37888
		info->size = size;
Packit d37888
		info->next = NULL;
Packit d37888
		last->next = info;
Packit d37888
	}
Packit d37888
}
Packit d37888
Packit d37888
/* Provides detailed information about a process. */
Packit d37888
Packit d37888
void
Packit d37888
glibtop_get_proc_mem_p (glibtop *server, glibtop_proc_mem *buf,
Packit d37888
			pid_t pid)
Packit d37888
{
Packit d37888
	task_basic_info_data_t tinfo;
Packit d37888
        mach_msg_type_number_t info_count;
Packit d37888
	vm_size_t vsize, resident, private, vprivate, shared;
Packit d37888
	kern_return_t retval;
Packit d37888
	shared_table stable;
Packit d37888
	vm_address_t address;
Packit d37888
	mach_port_t task;
Packit d37888
	int i, split;
Packit d37888
Packit d37888
	glibtop_init_p (server, (1 << GLIBTOP_SYSDEPS_PROC_MEM), 0);
Packit d37888
Packit d37888
	memset (buf, 0, sizeof (glibtop_proc_mem));
Packit d37888
Packit d37888
	address = 0;
Packit d37888
	split = 0;
Packit d37888
	vsize = resident = private = vprivate = shared = 0;
Packit d37888
	shared_table_init (stable);
Packit d37888
Packit d37888
	/* !!! THE FOLLOWING CODE RUNS SUID ROOT - CHANGE WITH CAUTION !!! */
Packit d37888
Packit d37888
	glibtop_suid_enter (server);
Packit d37888
	retval = task_for_pid (mach_task_self (), pid, &task);
Packit d37888
	glibtop_suid_leave (server);
Packit d37888
Packit d37888
	/* !!! END OF SUID ROOT PART !!! */
Packit d37888
Packit d37888
	if (retval)
Packit d37888
		return;
Packit d37888
Packit d37888
	info_count = TASK_BASIC_INFO_COUNT;
Packit d37888
	if (task_info (task, TASK_BASIC_INFO, (task_info_t)&tinfo, &info_count)) {
Packit d37888
		glibtop_warn_io_r (server, "task_info (procmem)");
Packit d37888
		return;
Packit d37888
	}
Packit d37888
	vsize = tinfo.virtual_size;
Packit d37888
	resident = tinfo.resident_size;
Packit d37888
Packit d37888
	/* !!! THE FOLLOWING CODE RUNS SUID ROOT - CHANGE WITH CAUTION !!! */
Packit d37888
Packit d37888
	glibtop_suid_enter (server);
Packit d37888
	while (1) {
Packit d37888
		vm_region_basic_info_data_64_t basic;
Packit d37888
		vm_region_top_info_data_t top;
Packit d37888
		mach_port_t object_name;
Packit d37888
		vm_size_t size;
Packit d37888
Packit d37888
		info_count = VM_REGION_BASIC_INFO_COUNT_64;
Packit d37888
		if (vm_region_64 (task, &address, &size, VM_REGION_BASIC_INFO,
Packit d37888
				  (vm_region_info_t)&basic,
Packit d37888
				  &info_count, &object_name))
Packit d37888
			break;
Packit d37888
Packit d37888
		info_count = VM_REGION_TOP_INFO_COUNT;
Packit d37888
		if (vm_region_64 (task, &address, &size, VM_REGION_TOP_INFO,
Packit d37888
			       (vm_region_info_t)&top,
Packit d37888
			       &info_count, &object_name))
Packit d37888
			break;
Packit d37888
Packit d37888
		if (address >= TEXT_SEGMENT_START && address < DATA_SEGMENT_END) {
Packit d37888
			if (!split && top.share_mode == SM_EMPTY) {
Packit d37888
				if (basic.reserved)
Packit d37888
					split = 1;
Packit d37888
			}
Packit d37888
			if (top.share_mode != SM_PRIVATE) {
Packit d37888
				address += size;
Packit d37888
				continue;
Packit d37888
			}
Packit d37888
		}
Packit d37888
Packit d37888
		switch (top.share_mode) {
Packit d37888
		case SM_COW:
Packit d37888
			if (top.ref_count == 1) {
Packit d37888
				private += top.private_pages_resident * vm_page_size;
Packit d37888
				private += top.shared_pages_resident * vm_page_size;
Packit d37888
				vprivate += size;
Packit d37888
			} else {
Packit d37888
				shared_table_register (server, stable, &top, size);
Packit d37888
				vprivate += top.private_pages_resident * vm_page_size;
Packit d37888
			}
Packit d37888
			break;
Packit d37888
		case SM_PRIVATE:
Packit d37888
			private += top.private_pages_resident * vm_page_size;
Packit d37888
			vprivate += size;
Packit d37888
			break;
Packit d37888
		case SM_SHARED:
Packit d37888
			shared_table_register (server, stable, &top, size);
Packit d37888
			break;
Packit d37888
		}
Packit d37888
Packit d37888
		address += size;
Packit d37888
	}
Packit d37888
	glibtop_suid_leave (server);
Packit d37888
Packit d37888
	/* !!! END OF SUID ROOT PART !!! */
Packit d37888
Packit d37888
	for (i = 0; i < SHARED_TABLE_SIZE; i++) {
Packit d37888
		shared_info *sinfo = &stable[i];
Packit d37888
Packit d37888
		while (sinfo) {
Packit d37888
			if (sinfo->share_mode == SM_SHARED &&
Packit d37888
			    sinfo->ref_count == sinfo->task_ref_count) {
Packit d37888
				private += sinfo->page_count * vm_page_size;
Packit d37888
				vprivate += sinfo->size;
Packit d37888
			} else {
Packit d37888
				shared += sinfo->page_count * vm_page_size;
Packit d37888
			}
Packit d37888
			sinfo = sinfo->next;
Packit d37888
		}
Packit d37888
	}
Packit d37888
	shared_table_free (server, stable);
Packit d37888
Packit d37888
	if (split)
Packit d37888
		vsize -= DATA_SEGMENT_END - TEXT_SEGMENT_START;
Packit d37888
Packit d37888
	buf->size     = vprivate;
Packit d37888
	buf->vsize    = vsize;
Packit d37888
	buf->resident = resident;
Packit d37888
	buf->share    = shared;
Packit d37888
	buf->rss      = private;
Packit d37888
	buf->flags    = _glibtop_sysdeps_proc_mem;
Packit d37888
}