Exemplo n.º 1
0
void
MemoryMap::eraseZeros(size_t minsize)
{
    if (isEmpty())
        return;
    unsigned permissions = READABLE | EXECUTABLE;       // access permissions that must be present
    AddressIntervalSet toRemove;                        // to save up intervals until we're done iterating
    AddressInterval zeroInterval;
    uint8_t buf[8192];
    rose_addr_t va = hull().least();
    while (AddressInterval accessed = atOrAfter(va).require(permissions).limit(sizeof buf).read(buf)) {
        for (size_t offset=0; offset<accessed.size(); ++offset) {
            if (0 == buf[offset]) {
                if (zeroInterval.isEmpty()) {
                    zeroInterval = AddressInterval(accessed.least()+offset);
                } else if (zeroInterval.greatest()+1 < offset) {
                    if (zeroInterval.size() >= minsize)
                        toRemove.insert(zeroInterval);
                    zeroInterval = AddressInterval(accessed.least()+offset);
                } else {
                    zeroInterval = AddressInterval::hull(zeroInterval.least(), zeroInterval.greatest()+1);
                }
            } else if (!zeroInterval.isEmpty()) {
                if (zeroInterval.size() >= minsize)
                    toRemove.insert(zeroInterval);
                zeroInterval = AddressInterval();
            }
        }
        if (accessed.greatest() == hull().greatest())
            break;                                      // prevent overflow in next statement
        va += accessed.size();
    }
    if (zeroInterval.size() >= minsize)
        toRemove.insert(zeroInterval);
    BOOST_FOREACH (const AddressInterval &interval, toRemove.intervals())
        erase(interval);
}
Exemplo n.º 2
0
Sawyer::Optional<rose_addr_t>
MemoryMap::findSequence(const AddressInterval &interval, const std::vector<uint8_t> &sequence) const {
    if (interval.isEmpty())
        return Sawyer::Nothing();
    if (sequence.empty())
        return interval.least();
    std::vector<uint8_t> buffer(4096);                  // size is arbitrary
    ASSERT_require2(sequence.size() <= buffer.size(), "long sequences not implemented yet");
    rose_addr_t searchVa = interval.least();
    while (AddressInterval window = atOrAfter(searchVa).read(buffer)) {
        for (size_t offset=0; offset+sequence.size()<=window.size(); ++offset) {
            if (std::equal(sequence.begin(), sequence.end(), &buffer[offset]))
                return window.least() + offset;
        }
        if (window.size()==buffer.size()) {
            searchVa = window.greatest() - buffer.size() + 2; // search for sequence that overlaps window boundary
        } else if (window.greatest() == hull().greatest()) {
            break;                                      // avoid possible overflow
        } else {
            searchVa = window.greatest() + 1;
        }
    }
    return Sawyer::Nothing();
}
Exemplo n.º 3
0
Extent toExtent(const AddressInterval &x) {
    return x.isEmpty() ? Extent() : Extent::inin(x.least(), x.greatest());
}
Exemplo n.º 4
0
// FIXME[Robb P. Matzke 2014-10-09]: No idea how to do this in Microsoft Windows!
void
MemoryMap::insertProcess(const std::string &locatorString) {
#ifdef BOOST_WINDOWS                                    // FIXME[Robb P. Matzke 2014-10-10]
    throw std::runtime_error("MemoryMap::insertProcess is not available on Microsoft Windows");
#else

    // Resources that need to be cleaned up on return or exception
    struct T {
        FILE *mapsFile;                                 // file for /proc/xxx/maps
        char *buf;                                      // line read from /proc/xxx/maps
        size_t bufsz;                                   // bytes allocated for "buf"
        int memFile;                                    // file for /proc/xxx/mem
        pid_t resumeProcess;                            // subordinate process to resume
        T(): mapsFile(NULL), buf(NULL), bufsz(0), memFile(-1), resumeProcess(-1) {}
        ~T() {
            if (mapsFile)
                fclose(mapsFile);
            if (buf)
                free(buf);
            if (memFile>=0)
                close(memFile);
            if (resumeProcess != -1)
                ptrace(PTRACE_DETACH, resumeProcess, 0, 0);
        }
    } local;

    // Parse the locator string.
    bool doAttach = true;
    const char *s = locatorString.c_str();
    if (':'!=*s++)
        throw insertProcessError(locatorString, "initial colon expected");
    while (':'!=*s) {
        if (boost::starts_with(s, "noattach")) {
            doAttach = false;
            s += strlen("noattach");
        } else {
            throw insertProcessError(locatorString, "unknown option beginning at ...\"" + std::string(s) + "\"");
        }
        if (','==*s)
            ++s;
    }
    if (':'!=*s++)
        throw insertProcessError(locatorString, "second colon expected");
    
    int pid = parseInteger(locatorString, s /*in,out*/, "process ID expected");

    // We need to attach to the process with ptrace before we can read from its /proc/xxx/mem file.  We'll have
    // to detach if anything goes wrong or when we finish.
    if (doAttach) {
        if (-1 == ptrace(PTRACE_ATTACH, pid, 0, 0))
            throw insertProcessError(locatorString, "cannot attach: " + std::string(strerror(errno)));
        int wstat = 0;
        if (-1 == waitpid(pid, &wstat, 0))
            throw insertProcessError(locatorString, "cannot wait: " + std::string(strerror(errno)));
        if (WIFEXITED(wstat))
            throw insertProcessError(locatorString, "process exited before it could be read");
        if (WIFSIGNALED(wstat))
            throw insertProcessError(locatorString, "process died with " +
                                     boost::to_lower_copy(std::string(strsignal(WTERMSIG(wstat)))) +
                                     " before it could be read");
        local.resumeProcess = pid;
        ASSERT_require2(WIFSTOPPED(wstat) && WSTOPSIG(wstat)==SIGSTOP, "subordinate process did not stop");
    }

    // Prepare to read subordinate's memory
    std::string mapsName = "/proc/" + StringUtility::numberToString(pid) + "/maps";
    if (NULL==(local.mapsFile = fopen(mapsName.c_str(), "r")))
        throw insertProcessError(locatorString, "cannot open " + mapsName + ": " + strerror(errno));
    std::string memName = "/proc/" + StringUtility::numberToString(pid) + "/mem";
    if (-1 == (local.memFile = open(memName.c_str(), O_RDONLY)))
        throw insertProcessError(locatorString, "cannot open " + memName + ": " + strerror(errno));

    // Read each line from the /proc/xxx/maps to figure out what memory is mapped in the subordinate process. The format for
    // the part we're interested in is /^([0-9a-f]+)-([0-9a-f]+) ([-r][-w][-x])/ where $1 is the inclusive starting address, $2
    // is the exclusive ending address, and $3 are the permissions.
    int mapsFileLineNumber = 0;
    while (rose_getline(&local.buf, &local.bufsz, local.mapsFile)>0) {
        ++mapsFileLineNumber;

        // Begin address
        char *s=local.buf, *rest=s;
        errno = 0;
        rose_addr_t begin = rose_strtoull(s, &rest, 16);
        if (errno!=0 || rest==s || '-'!=*rest) {
            throw insertProcessError(locatorString, mapsName + " syntax error for beginning address at line " +
                                     StringUtility::numberToString(mapsFileLineNumber) + ": " + local.buf);
        }

        // End address
        s = rest+1;
        rose_addr_t end = rose_strtoull(s, &rest, 16);
        if (errno!=0 || rest==s || ' '!=*rest) {
            throw insertProcessError(locatorString, mapsName + " syntax error for ending address at line " +
                                     StringUtility::numberToString(mapsFileLineNumber) + ": " + local.buf);
        }
        if (begin >= end) {
            throw insertProcessError(locatorString, mapsName + " invalid address range at line " +
                                     StringUtility::numberToString(mapsFileLineNumber) + ": " + local.buf);
        }

        // Access permissions
        s = ++rest;
        if ((s[0]!='r' && s[0]!='-') || (s[1]!='w' && s[1]!='-') || (s[2]!='x' && s[2]!='-')) {
            throw insertProcessError(locatorString, mapsName + " invalid access permissions at line " +
                                     StringUtility::numberToString(mapsFileLineNumber) + ": " + local.buf);
        }
        unsigned accessibility = ('r'==s[0] ? READABLE : 0) | ('w'==s[1] ? WRITABLE : 0) | ('x'==s[2] ? EXECUTABLE : 0);

        // Skip over unused fields
        for (size_t nSpaces=0; nSpaces<4 && *s; ++s) {
            if (isspace(*s))
                ++nSpaces;
        }
        while (isspace(*s)) ++s;

        // Segment name according to the kernel
        std::string kernelSegmentName;
        while (*s && !isspace(*s))
            kernelSegmentName += *s++;

        // Create memory segment, but don't insert it until after we read all the data
        std::string segmentName = "proc:" + StringUtility::numberToString(pid);
        AddressInterval segmentInterval = AddressInterval::baseSize(begin, end-begin);
        Segment segment = Segment::anonymousInstance(segmentInterval.size(), accessibility,
                                                     segmentName + "(" + kernelSegmentName + ")");

        // Copy data from the subordinate process into our memory segment
        if (-1 == lseek(local.memFile, begin, SEEK_SET))
            throw insertProcessError(locatorString, memName + " seek failed: " + strerror(errno));
        size_t nRemain = segmentInterval.size();
        rose_addr_t segmentBufferOffset = 0;
        while (nRemain > 0) {
            uint8_t chunkBuf[8192];
            size_t chunkSize = std::min(nRemain, sizeof chunkBuf);
            ssize_t nRead = ::read(local.memFile, chunkBuf, chunkSize);
            if (-1==nRead) {
                if (EINTR==errno)
                    continue;
                //mlog[WARN] <<strerror(errno) <<" during read from " <<memName <<" for segment " <<kernelSegmentName
                //           <<" at " <<segmentInterval <<"\n";
                segmentName += "[" + boost::to_lower_copy(std::string(strerror(errno))) + "]";
                break;
            } else if (0==nRead) {
                //mlog[WARN] <<"short read from " <<memName <<" for segment " <<kernelSegmentName <<" at " <<segmentInterval <<"\n";
                segmentName += "[short read]";
                break;
            }
            rose_addr_t nWrite = segment.buffer()->write(chunkBuf, segmentBufferOffset, nRead);
            ASSERT_always_require(nWrite == (rose_addr_t)nRead);
            nRemain -= chunkSize;
            segmentBufferOffset += chunkSize;
        }
        if (nRemain > 0) {
            // If a read failed, map only what we could read
            segmentInterval = AddressInterval::baseSize(segmentInterval.least(), segmentInterval.size()-nRemain);
        }

        // Insert segment into memory map
        if (!segmentInterval.isEmpty())
            insert(segmentInterval, segment);
    }
#endif
}