/* Copyright Yann Weber This file is part of asmsh. asmsh is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. asmsh is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with asmsh. If not, see . */ #include "mmap_parse.h" void child_mmap_init(child_mmap_l *maps) { bzero(maps, sizeof(*maps)); } int child_mmap_get(pid_t child_pid, child_mmap_l *maps) { char procfs_path[PATH_MAX+1]; int ret, maps_fd; if(child_pid == -1) { errno = EINVAL; return -1; } ret = snprintf(procfs_path, PATH_MAX, "/proc/%d/maps", child_pid); if(ret < 0) { return -1; } procfs_path[ret] = '\0'; if((maps_fd = open(procfs_path, O_RDONLY)) < 0) { return -1; } if(child_mmap_get_fd(maps_fd, maps) < 0) { ret = -1; } else { ret = 0; } close(maps_fd); return ret; } int child_mmap_get_fd(int maps_fd, child_mmap_l *maps) { const int RDBUF_SZ = 4095; char rdbuf[RDBUF_SZ+1]; char *line, *endline; int ret; size_t curmap; void *tmp; curmap = 0; do { ret = read(maps_fd, rdbuf, RDBUF_SZ); if(ret < 0) { goto err; } else if(ret == 0) { break; } rdbuf[ret] = '\0'; line = endline = rdbuf; while(*endline) { if(*endline == '\n') { if(maps->size <= curmap) { if(_child_mmap_alloc(curmap, maps) < 0) { goto err; } } *endline = '\0'; ret = child_mmap_parseline(line, &maps->maps[curmap]); if(ret < 0) { goto err; } line = endline + 1; curmap++; } endline++; } }while(1); close(maps_fd); if(curmap < maps->size) { tmp = realloc(maps->maps, sizeof(child_mmap_t) * curmap); if(!tmp) { perror("err"); goto err; } maps->maps = tmp; maps->size = curmap; } return 0; err: ret = errno; close(maps_fd); errno = ret; return -1; } int child_mmap_parseline(char *line, child_mmap_t *maps) { char *orig, *endptr; unsigned long long parsed; int cperm; size_t i; int major; const char perms[3] = "rwx"; const int perms_val[3] = {PROT_READ, PROT_WRITE, PROT_EXEC}; #define parsefield(line, sep, base, mapfield) {\ unsigned long long p; char *endptr;\ errno = 0;\ p = strtoull(*line, &endptr, base);\ if(errno || *endptr != sep) {\ dprintf(2, "*line : '%s' %s\n", *line, #mapfield);\ if(errno != ERANGE) { errno=EINVAL; }\ goto err_inval;\ }\ *mapfield=(typeof(*mapfield))p;\ *line = endptr+1;\ } orig = line; parsefield(&line, '-', 16, &maps->start); parsefield(&line, ' ', 16, &maps->stop); cperm = 1; maps->perm = 0; for(i=0; i<3; i++) { if(*line == perms[i]) { maps->perm |= perms_val[i]; } else if (*line != '-') { goto err_inval; } line++; cperm <<= 1; } switch(*line) { case 'p': maps->perm |= MAP_PRIVATE; break; case 's': maps->perm |= MAP_SHARED; break; default: goto err_inval; } line++; parsefield(&line, ' ', 16, &maps->offset); parsefield(&line, ':', 10, &major); parsefield(&line, ' ', 10, &maps->device); maps->device |= major << 8; // WARNING : hardcoded major shift //parsefield(&line, ' ', 10, &maps->inode); errno = 0; parsed = strtoull(line, &endptr, 10); if(errno || (*endptr != ' ' && *endptr != '\0')) { if(errno != ERANGE) { errno = EINVAL; } goto err_inval; } maps->inode = parsed; line = endptr; while(*line==' ') { line++; } maps->pathname = strndup(line, PATH_MAX * 8); return 0; err_inval: dprintf(2, "Invalid procfs/[pid]/maps content '%s'", orig); return -1; } int _child_mmap_alloc(size_t curmap, child_mmap_l *maps) { void *tmp; maps->size++; if(curmap == 0) { tmp = malloc(sizeof(child_mmap_t)); } else { tmp = realloc(maps->maps, sizeof(child_mmap_t) * maps->size); } if(!tmp) { perror("Unable to allocate maps description"); return -1; } maps->maps = tmp; return 0; }