Skip to content

Commit

Permalink
collector: Fix dump_buffers on sparc
Browse files Browse the repository at this point in the history
The problem is two-fold:
- On Sparc, heap addresses have their MSB set. For example:

    [~]# cat /proc/self/maps
    00100000-0010a000 r-xp 00000000 fd:00 7340064                            /bin/cat
    0020a000-0020c000 rwxp 0000a000 fd:00 7340064                            /bin/cat
    0020c000-0022e000 rwxp 00000000 00:00 0                                  [heap]
    7feffe4e000-7feffe70000 rw-p 00000000 00:00 0                            [stack]
    fffffc0100000000-fffffc0100002000 rw-p 00000000 00:00 0
    fffffc0100004000-fffffc0100006000 rw-p 00000000 00:00 0
    fffffc010013c000-fffffc010013e000 r--p 00000000 00:00 0                  [vvar]
    fffffc010013e000-fffffc0100140000 r-xp 00000000 00:00 0                  [vdso]
    fffffc0100140000-fffffc01002c4000 r-xp 00000000 fd:00 5505039            /lib64/libc-2.12.so
    fffffc01002c4000-fffffc01003c4000 ---p 00184000 fd:00 5505039            /lib64/libc-2.12.so
    fffffc01003c4000-fffffc01003c8000 r--p 00184000 fd:00 5505039            /lib64/libc-2.12.so
    fffffc01003c8000-fffffc01003ce000 rwxp 00188000 fd:00 5505039            /lib64/libc-2.12.so
    fffffc01003ce000-fffffc01003d2000 rwxp 00000000 00:00 0
    fffffc0102fac000-fffffc0102fd0000 r-xp 00000000 fd:00 5505236            /lib64/ld-2.12.so
    fffffc01030d0000-fffffc01030d2000 r--p 00024000 fd:00 5505236            /lib64/ld-2.12.so
    fffffc01030d2000-fffffc01030d4000 rwxp 00026000 fd:00 5505236            /lib64/ld-2.12.so
    fffffc01030d4000-fffffc0108f6c000 r--p 00000000 fd:00 13126552           /usr/lib/locale/locale-archive

- Linux's pread() implementation has a limitation: it treats the offset
argument as a signed offset, hence it can't access the top half of the
memory space:

    SYSCALL_DEFINE(pread64)(unsigned int fd, char __user *buf,
                            size_t count, loff_t pos)
    {
            struct file *file;
            ssize_t ret = -EBADF;
            int fput_needed;
            if (pos < 0)
                    return -EINVAL;
            file = fget_light(fd, &fput_needed);
            if (file) {
                    ret = -ESPIPE;
                    if (file->f_mode & FMODE_PREAD)
                            ret = vfs_read(file, buf, count, &pos);
                    fput_light(file, fput_needed);
            }
            return ret;
    }

So the problem with bootchart-collector using pread() to read from
/dev/{pid}/mem becomes obvious: the first call to pread() successfully
reads from the stack, but subsequent calls fail reading from the heap
and return value EINVAL.

The fix is to replace the call to pread() by two system calls: lseek()
which can handle unsigned offsets and read().
There is no real performance degradation and it is portable.
  • Loading branch information
[email protected] authored and xrmx committed Nov 19, 2015
1 parent eac1748 commit 136149d
Showing 1 changed file with 2 additions and 1 deletion.
3 changes: 2 additions & 1 deletion collector/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ static void dump_buffers (DumpState *s)
Chunk *c = (Chunk *)&buffer;
size_t addr = (size_t) s->map.chunks[i];

pread (s->mem, &buffer, CHUNK_SIZE, addr);
lseek (s->mem, addr, SEEK_SET);
read (s->mem, &buffer, CHUNK_SIZE);
/* log ("type: '%s' len %d\n",
c->dest_stream, (int)c->length); */

Expand Down

0 comments on commit 136149d

Please sign in to comment.