Dump de memoria de otro proceso

Astor Giacomo agiacom en optonline.net
Mie Ago 24 02:41:01 CLT 2005


On Tuesday 23 August 2005 05:29 pm, Bernardo Suarez wrote:

[Mis disculpas de antemano si mensajes como este no son bienvenidos en
esta lista. En ese caso no repetire la ofensa!]

[...]
> Por lo tanto me ayudaría mucho alguna utilidad que me permita hacer un
> dump hexadecimal de la memoria usada por otro proceso. Como no he
> podido detectar que parte del programa se come la memoria, quizas sea
> una buena pista saber con que la estoy llenando... Alguien
> tiene/conoce/sabe como hacer algo así?

Perl es conocido por ser extremadamente ineficiente en lo que a uso de memoria 
se refiere.

Puedes tratar con lo de mas abajo. Aunque escrito a la rapida y, por eso, 
bastante rustico, hace lo que necesitas (o pareces necesitar).

$ gcc -o memdump memdump.c
$ cat /proc/$$/maps
[...]
049bc000-049be000 rw-p 049bc000 00:00 0
08047000-080d8000 r-xp 00000000 03:41 145525     /bin/bash
080d8000-080de000 rw-p 00090000 03:41 145525     /bin/bash
080de000-080e3000 rw-p 080de000 00:00 0
09bea000-09c2c000 rw-p 09bea000 00:00 0  <-- el "heap"
b7de1000-b7de3000 rw-p b7de1000 00:00 0
[...]
$ ./memdump $$ 0x09bea000
[...]

Ojo que al terminar `memdump' con ^C o con "q" en less(1)
tienes que continuar manualmente el otro proceso (con 
kill -CONT $pid). Arreglar eso es tarea para el lector :-)

Ocioso a las 2:20am,
-ag

---
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/ptrace.h>

#define SYSERR(x,t) \
        if ((x) < 0) { perror(t); pexit(1); }
pid_t mem_pid = 0;

void pexit(int x)
{
        if (mem_pid) ptrace(PTRACE_DETACH, mem_pid, 0, 0);
        exit(x);
}

void memdump(int f, off_t offset, int bin)
{
        unsigned char data[16];
        int sofar = 0, n, k;

        SYSERR(lseek(f, offset, SEEK_SET), "lseek");        
        while ((n = read(f, data, sizeof(data))) > 0) {
                const unsigned char *p;
                if (bin) {
                        write(1, data, n);
                        continue;
                }
                printf("%08lx - ", offset + sofar);
                for (p = data; p < &data[n]; p++)
                        printf("%02x ", *p);
                printf("| ");
                for (p = data; p < &data[n]; p++)
                        printf("%c", isprint(*p) ? *p : '.');
                putchar('\n');
                sofar += n;
        }
}

int main(int argc, char **argv)
{
        int r, status, fd, bin;
        pid_t pid;
        off_t off;
        char buf[32];

        if (argc < 3) {
                printf("Usage: %s PID ADDRESS\n", argv[0]);
                exit(1);
        }
        pid = atoi(argv[1]);
        off = (off_t)strtol(argv[2], 0, 0);
        bin = argv[3] ? atoi(argv[3]) : 0;
        
        snprintf(buf, sizeof(buf), "/proc/%u/mem", pid);
        SYSERR(fd = open(buf, O_RDONLY), buf);
        SYSERR(r = ptrace(PTRACE_ATTACH, pid, 0, 0), "ptrace");
        while ((r = waitpid(pid, &status, WUNTRACED)) < 0 && errno == EINTR)
                ;
        mem_pid = pid;
        SYSERR(r, "waitpid");
        if (!WIFSTOPPED(status)) {
                fprintf(stderr, "Child not stopped!?\n");
                exit(1);
        }
        memdump(fd, off, bin);
        close(fd);
        pexit(0);
}



Más información sobre la lista de distribución Linux