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.
25 #include <pagemap/pagemap.h>
29 static int read_maps(pm_process_t *proc);
31 #define MAX_FILENAME 64
33 int pm_process_create(pm_kernel_t *ker, pid_t pid, pm_process_t **proc_out) {
35 char filename[MAX_FILENAME];
38 if (!ker || !proc_out)
41 proc = calloc(1, sizeof(*proc));
48 error = snprintf(filename, MAX_FILENAME, "/proc/%d/pagemap", pid);
49 if (error < 0 || error >= MAX_FILENAME) {
50 error = (error < 0) ? (errno) : (-1);
55 proc->pagemap_fd = open(filename, O_RDONLY);
56 if (proc->pagemap_fd < 0) {
62 error = read_maps(proc);
73 int pm_process_usage_flags(pm_process_t *proc, pm_memusage_t *usage_out,
74 uint64_t flags_mask, uint64_t required_flags)
76 pm_memusage_t usage, map_usage;
80 if (!proc || !usage_out)
83 pm_memusage_zero(&usage);
84 pm_memusage_pswap_init_handle(&usage, usage_out->p_swap);
86 pm_memusage_zero(&map_usage);
87 pm_memusage_pswap_init_handle(&map_usage, usage_out->p_swap);
89 for (i = 0; i < proc->num_maps; i++) {
90 error = pm_map_usage_flags(proc->maps[i], &map_usage, flags_mask,
92 if (error) return error;
94 pm_memusage_add(&usage, &map_usage);
97 memcpy(usage_out, &usage, sizeof(pm_memusage_t));
103 int pm_process_usage(pm_process_t *proc, pm_memusage_t *usage_out) {
104 return pm_process_usage_flags(proc, usage_out, 0, 0);
107 int pm_process_pagemap_range(pm_process_t *proc,
108 uint64_t low, uint64_t high,
109 uint64_t **range_out, size_t *len) {
116 if (!proc || (low > high) || !range_out || !len)
125 firstpage = low / proc->ker->pagesize;
126 numpages = (high - low) / proc->ker->pagesize;
128 range = malloc(numpages * sizeof(uint64_t));
132 off = lseek64(proc->pagemap_fd, firstpage * sizeof(uint64_t), SEEK_SET);
133 if (off == (off_t)-1) {
138 error = read(proc->pagemap_fd, (char*)range, numpages * sizeof(uint64_t));
140 /* EOF, mapping is not in userspace mapping range (probably vectors) */
145 } else if (error < 0 || (error > 0 && error < (int)(numpages * sizeof(uint64_t)))) {
146 error = (error < 0) ? errno : -1;
157 int pm_process_maps(pm_process_t *proc, pm_map_t ***maps_out, size_t *len) {
160 if (!proc || !maps_out || !len)
163 if (proc->num_maps) {
164 maps = malloc(proc->num_maps * sizeof(pm_map_t*));
168 memcpy(maps, proc->maps, proc->num_maps * sizeof(pm_map_t*));
174 *len = proc->num_maps;
179 int pm_process_workingset(pm_process_t *proc,
180 pm_memusage_t *ws_out, int reset) {
181 pm_memusage_t ws, map_ws;
182 char filename[MAX_FILENAME];
191 pm_memusage_zero(&ws);
192 pm_memusage_pswap_init_handle(&ws, ws_out->p_swap);
194 pm_memusage_zero(&map_ws);
195 pm_memusage_pswap_init_handle(&map_ws, ws_out->p_swap);
197 for (i = 0; i < proc->num_maps; i++) {
198 error = pm_map_workingset(proc->maps[i], &map_ws);
199 if (error) return error;
201 pm_memusage_add(&ws, &map_ws);
204 memcpy(ws_out, &ws, sizeof(ws));
208 error = snprintf(filename, MAX_FILENAME, "/proc/%d/clear_refs",
210 if (error < 0 || error >= MAX_FILENAME) {
211 return (error < 0) ? (errno) : (-1);
214 fd = open(filename, O_WRONLY);
218 write(fd, "1\n", strlen("1\n"));
226 int pm_process_destroy(pm_process_t *proc) {
232 for (i = 0; i < proc->num_maps; i++) {
233 pm_map_destroy(proc->maps[i]);
236 close(proc->pagemap_fd);
242 #define INITIAL_MAPS 10
245 static int read_maps(pm_process_t *proc) {
246 char filename[MAX_FILENAME];
248 size_t line_length = 0;
249 char perms[MAX_PERMS];
251 pm_map_t *map, **maps, **new_maps;
252 int maps_count, maps_size;
258 maps = calloc(INITIAL_MAPS, sizeof(pm_map_t*));
261 maps_count = 0; maps_size = INITIAL_MAPS;
263 error = snprintf(filename, MAX_FILENAME, "/proc/%d/maps", proc->pid);
264 if (error < 0 || error >= MAX_FILENAME) {
266 return (error < 0) ? (errno) : (-1);
269 maps_f = fopen(filename, "r");
275 while (getline(&line, &line_length, maps_f) != -1) {
276 line[strlen(line) - 1] = '\0'; // Lose the newline.
278 if (maps_count >= maps_size) {
279 new_maps = realloc(maps, 2 * maps_size * sizeof(pm_map_t*));
291 maps[maps_count] = map = calloc(1, sizeof(*map));
296 sscanf(line, "%" SCNx64 "-%" SCNx64 " %4s %" SCNx64 " %*s %*d %n",
297 &map->start, &map->end, perms, &map->offset, &name_offset);
299 map->name = strdup(line + name_offset);
302 for (; maps_count > 0; maps_count--)
303 pm_map_destroy(maps[maps_count]);
310 if (perms[0] == 'r') map->flags |= PM_MAP_READ;
311 if (perms[1] == 'w') map->flags |= PM_MAP_WRITE;
312 if (perms[2] == 'x') map->flags |= PM_MAP_EXEC;
320 new_maps = realloc(maps, maps_count * sizeof(pm_map_t*));
321 if (maps_count && !new_maps) {
327 proc->maps = new_maps;
328 proc->num_maps = maps_count;