2 * Copyright (C) 2008 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
24 #include <pagemap/pagemap.h>
28 static int read_maps(pm_process_t *proc);
30 #define MAX_FILENAME 64
32 int pm_process_create(pm_kernel_t *ker, pid_t pid, pm_process_t **proc_out) {
34 char filename[MAX_FILENAME];
37 if (!ker || !proc_out)
40 proc = calloc(1, sizeof(*proc));
47 error = snprintf(filename, MAX_FILENAME, "/proc/%d/pagemap", pid);
48 if (error < 0 || error >= MAX_FILENAME) {
49 error = (error < 0) ? (errno) : (-1);
54 proc->pagemap_fd = open(filename, O_RDONLY);
55 if (proc->pagemap_fd < 0) {
61 error = read_maps(proc);
72 int pm_process_usage(pm_process_t *proc, pm_memusage_t *usage_out) {
73 pm_memusage_t usage, map_usage;
77 if (!proc || !usage_out)
80 pm_memusage_zero(&usage);
82 for (i = 0; i < proc->num_maps; i++) {
83 error = pm_map_usage(proc->maps[i], &map_usage);
84 if (error) return error;
86 pm_memusage_add(&usage, &map_usage);
89 memcpy(usage_out, &usage, sizeof(pm_memusage_t));
94 int pm_process_pagemap_range(pm_process_t *proc,
95 unsigned long low, unsigned long high,
96 uint64_t **range_out, size_t *len) {
97 int firstpage, numpages;
103 if (!proc || (low >= high) || !range_out || !len)
106 firstpage = low / proc->ker->pagesize;
107 numpages = (high - low) / proc->ker->pagesize;
109 range = malloc(numpages * sizeof(uint64_t));
113 off = lseek(proc->pagemap_fd, firstpage * sizeof(uint64_t), SEEK_SET);
114 if (off == (off_t)-1) {
119 len_read = read(proc->pagemap_fd, (char*)range, numpages * sizeof(uint64_t));
120 if (len_read < (ssize_t)numpages * sizeof(uint64_t)) {
121 error = (error < 0) ? errno : -1;
132 int pm_process_maps(pm_process_t *proc, pm_map_t ***maps_out, int *len) {
135 if (!proc || !maps_out || !len)
138 if (proc->num_maps) {
139 maps = malloc(proc->num_maps * sizeof(pm_map_t*));
143 memcpy(maps, proc->maps, proc->num_maps * sizeof(pm_map_t*));
149 *len = proc->num_maps;
154 int pm_process_workingset(pm_process_t *proc,
155 pm_memusage_t *ws_out, int reset) {
156 pm_memusage_t ws, map_ws;
157 char filename[MAX_FILENAME];
166 pm_memusage_zero(&ws);
167 for (i = 0; i < proc->num_maps; i++) {
168 error = pm_map_workingset(proc->maps[i], &map_ws);
169 if (error) return error;
171 pm_memusage_add(&ws, &map_ws);
174 memcpy(ws_out, &ws, sizeof(ws));
178 error = snprintf(filename, MAX_FILENAME, "/proc/%d/clear_refs",
180 if (error < 0 || error >= MAX_FILENAME) {
181 return (error < 0) ? (errno) : (-1);
184 fd = open(filename, O_WRONLY);
188 write(fd, "1\n", strlen("1\n"));
196 int pm_process_destroy(pm_process_t *proc) {
201 close(proc->pagemap_fd);
207 #define INITIAL_MAPS 10
218 static int read_maps(pm_process_t *proc) {
219 char filename[MAX_FILENAME];
220 char line[MAX_LINE], name[MAX_LINE], perms[MAX_PERMS];
222 pm_map_t *map, **maps, **new_maps;
223 int maps_count, maps_size;
229 maps = calloc(INITIAL_MAPS, sizeof(pm_map_t*));
232 maps_count = 0; maps_size = INITIAL_MAPS;
234 error = snprintf(filename, MAX_FILENAME, "/proc/%d/maps", proc->pid);
235 if (error < 0 || error >= MAX_FILENAME)
236 return (error < 0) ? (errno) : (-1);
238 maps_f = fopen(filename, "r");
242 while (fgets(line, MAX_LINE, maps_f)) {
243 if (maps_count >= maps_size) {
244 new_maps = realloc(maps, 2 * maps_size * sizeof(pm_map_t*));
255 maps[maps_count] = map = calloc(1, sizeof(*map));
259 sscanf(line, "%lx-%lx %s %lx %*s %*d %" S(MAX_LINE) "s",
260 &map->start, &map->end, perms, &map->offset, name);
262 map->name = malloc(strlen(name) + 1);
265 for (; maps_count > 0; maps_count--)
266 pm_map_destroy(maps[maps_count]);
270 strcpy(map->name, name);
271 if (perms[0] == 'r') map->flags |= PM_MAP_READ;
272 if (perms[1] == 'w') map->flags |= PM_MAP_WRITE;
273 if (perms[2] == 'x') map->flags |= PM_MAP_EXEC;
280 new_maps = realloc(maps, maps_count * sizeof(pm_map_t*));
281 if (maps_count && !new_maps) {
287 proc->maps = new_maps;
288 proc->num_maps = maps_count;