MiniMax
MiniMax

Reputation: 1093

Reading /proc/pid/mem file returns nothing

I want to catch the memory mapping of current process to a file by reading the content of /proc/pid/mem and writing it to another file. But the resulting file is empty every time. I use sudo, so I have no permission errors. When I change the input file to some testing file, like "test_file_1.txt", all works as expected. What I do wrong?

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(int argc, char *argv[], char *envp[]) {
    char filename[100];

    pid_t pid = getpid();
    printf("pid: %i\n", pid);

////It works with an usual file
//  FILE *in_file = fopen("test_file_1.txt", "r");

////But doesn't work with this:
    sprintf(filename, "/proc/%i/mem", pid);
    FILE *in_file = fopen(filename, "r");
    if(!in_file){
        puts("in_file can't be opened");
    }

    sprintf(filename, "mem_%i.txt", pid);
    FILE *out_file = fopen(filename, "w");
    if(!out_file){
        puts("out_file can't be opened");
    }

    char line[500];
    while(fgets(line, 500, in_file)) {
        fputs(line, out_file);             
    }

    fclose(in_file);
    fclose(out_file);

    return 0;
}

Upvotes: 2

Views: 4215

Answers (3)

user10678532
user10678532

Reputation:

Instead of proc/<pid>/mem, you should use process_vm_readv(2).

Really.

/proc/<pid>/mem is a legacy interface, which is still cute to use with dd from the shell ("everything is a file", etc), but it makes no point to bother with it from C.

Upvotes: 3

/proc/PID/mem gives access to the memory of the process as it is mapped in the process: accessing the Nth byte of this file is equivalent to accessing (*unsigned char)N inside the process in C, or ptrace(PTRACE_PEEKDATA, PID, (void*)N, NULL) from another process (or PTRACE_POKEDATA for writing, and with the difference that ptrace accesses one word at a time, not one byte at a time).

Processes usually have nothing mapped at address 0. When you open the file and start reading, you're reading from address 0. Since there's nothing there, the read call returns EIO. Use perror to get more information about the failure of fgets.

Note that fgets won't let you read from /proc/PID/mem because it contains binary data, but fgets only works on text (strings that don't contain null bytes). Use open, lseek and read to read from /proc/PID/mem.

Before reading from /proc/PID/mem, you need to figure out where the process has things mapped. This information is in /proc/PID/maps. This file is in a text file with reasonable line lengths, so using fopen and fgets is fine.

If you're accessing the process's own memory, you can use /proc/self/… instead of interpolating the PID.

FILE *maps_file = fopen("/proc/self/maps", "r");
if (maps_file == NULL) {perror("/proc/self/maps"); exit(EXIT_FAILURE);}
char line[500];
while (fgets(line, sizeof(line), maps_file)) { ... }
fclose(maps_file);

Upvotes: 3

kprow
kprow

Reputation: 84

Try looking at /proc/pid/maps to see if that file has the memory mapping info you are looking for.

Upvotes: 1

Related Questions