<commit_before>/**************************************************************************
 *
 * Copyright 2013 Samsung
 * Contributed by Eugene Velesevich
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

/*
 *  Wrapper for platform-specific code for obtaining symbolic backtraces
 *  on Android and Linux
 */

#include "trace_backtrace.hpp"

#if defined(ANDROID) or defined(__linux__)

#include <set>
#include "os.hpp"

namespace trace {

/*
 * Pascal string (with zero terminator optionally omitted)
 * This is a helper class for storing a set of exact strings or prefixes
 * to match a zero-terminated string against later.
 * Two zero-terminated pstrings compare equal iff they are the same.
 * Otherwise, they compare equal iff one is a prefix of the other
 * (a zero-terminated pstring cannot be a prefix)
 */

struct pstring {
    const char* s;
    int n;
    pstring(const char* s, int n)
    {
        this->s = s;
        this->n = n;
    }
    bool operator<(const pstring q2) const
    {
        return memcmp(s, q2.s, n < q2.n? n : q2.n) < 0;
    }
};

class StringPrefixes {
private:
    std::set<pstring> pset;

    void addPrefix(char* startbuf, int n) {
        std::set<pstring>::iterator elem = pset.find(pstring(startbuf, n));
        bool replace = elem != pset.end() && n < elem->n;
        if (replace) {
            pset.erase(elem);
        }
        if (replace || elem == pset.end()) {
            pset.insert(pstring(startbuf, n));
        }
    }
public:
    StringPrefixes();

    bool contain(const char* s) {
        return pset.find(pstring(s, strlen(s) + 1)) != pset.end();
    }
};

StringPrefixes::StringPrefixes() {
    char *list = getenv("APITRACE_BACKTRACE");
    if (!list)
        return;
    for (char *t = strdup(list); ; t = NULL) {
        char *tok = strtok(t, " \t\r\n");
        if (!tok)
            break;
        if (tok[0] == '#')
            continue;
        if (tok[strlen(tok) - 1] == '*')
            addPrefix(tok, strlen(tok) - 1);
        else
            addPrefix(tok, strlen(tok) + 1);
    }
}

bool backtrace_is_needed(const char* fname) {
    static StringPrefixes backtraceFunctionNamePrefixes;
    return backtraceFunctionNamePrefixes.contain(fname);
}

} /* namespace trace */

#ifdef ANDROID

#include <dlfcn.h>
#include "os.hpp"
#include <vector>

namespace trace {

/* The following two declarations are copied from Android sources */

enum DebugTargetKind {
    kDebugTargetUnknown = 0,
    kDebugTargetLog,
    kDebugTargetFile,
};

struct DebugOutputTarget {
    DebugTargetKind which;

    union {
        struct {
            int priority;
            const char* tag;
        } log;
        struct {
            FILE* fp;
        } file;
    } data;
};

#define THREAD_SELF_NAME "_Z13dvmThreadSelfv"
#define CREATE_DEBUG_TARGET_NAME "_Z25dvmCreateFileOutputTargetP17DebugOutputTargetP7__sFILE"
#define DUMP_BACKTRACE_NAME "_Z18dvmDumpThreadStackPK17DebugOutputTargetP6Thread"

class DalvikBacktraceProvider {
private:
    bool errorOccured;
    void* (*threadself)(void);
    FILE* streamInMemory;
    char* buf;
    size_t bufSize;
    void (*dumpBacktrace)(const DebugOutputTarget*, void*);
    DebugOutputTarget debugTarget;
    Id nextFrameId;
public:
    DalvikBacktraceProvider() {
        nextFrameId = 0;
        FILE* (*open_memstream_exp)(char**, size_t*);
        void (*createDebugTarget)(DebugOutputTarget*, FILE*);
        void* handle = dlopen("/system/lib/libdvm.so", 0);
        errorOccured = true;
        if (!handle) {
            os::log("dlopen failed\n");
            return;
        }
        threadself = (void* (*)())dlsym(handle, THREAD_SELF_NAME);
        if (threadself == NULL) {
            os::log("dlsym ThreadSelf failed\n");
            return;
        }
        createDebugTarget = (void (*)(DebugOutputTarget*, FILE*))dlsym(handle, CREATE_DEBUG_TARGET_NAME);
        if (createDebugTarget == NULL) {
            os::log("dlsym CreateFileOutput failed\n");
            return;
        }
        dumpBacktrace = (void (*)(const DebugOutputTarget*, void*))dlsym(handle, DUMP_BACKTRACE_NAME);
        if (dumpBacktrace == NULL) {
            os::log("dlsym DumpThreadStack failed\n");
            return;
        }
        void* handle2 = dlopen("/system/lib/libcutils.so", 0);
        if (!handle2) {
            os::log("dlopen failed\n");
            return;
        }
        open_memstream_exp = (FILE* (*)(char**, size_t*))dlsym(handle2, "open_memstream");
        if (open_memstream_exp == NULL) {
            os::log("dlsym open_memstream failed\n");
            return;
        }
        streamInMemory = open_memstream_exp(&buf, &bufSize);
        if (streamInMemory == NULL) {
            os::log("open_memstream failed\n");
            return;
        }
        createDebugTarget(&debugTarget, streamInMemory);
        errorOccured = false;
    }

    inline char* getBacktrace() {
        if (errorOccured) {
            return NULL;
        }
        rewind(streamInMemory);
        dumpBacktrace(&debugTarget, threadself());
        fflush(streamInMemory);
        return buf;
    }
/*
 * Parse a stack frame, expecting:
 * "  at android.view.HardwareRenderer$GlRenderer.initializeEgl(HardwareRenderer.java:547)"
 * or
 * "  at android.view.HardwareRenderer$GlRenderer.initializeEgl(Native Method)"
 */
    std::vector<RawStackFrame> parseBacktrace(char *rawBacktrace) {
        std::vector<RawStackFrame> parsedBacktrace;
        char* rawBacktrace_it = rawBacktrace;
        while (*rawBacktrace_it != '\0') {
            RawStackFrame stackFrame;
            // TODO: Keep a cache of stack frames
            stackFrame.id = nextFrameId++;
            /* skip leading space */
            while (*rawBacktrace_it == ' ') {
                rawBacktrace_it++;
            }
            /* Skip "at " */
            rawBacktrace_it += 3;
            stackFrame.function = rawBacktrace_it;
            while (*rawBacktrace_it != '(') {
                rawBacktrace_it++;
            }
            *rawBacktrace_it = '\0';
            stackFrame.filename = rawBacktrace_it + 1;
            while (*rawBacktrace_it != ':' && *rawBacktrace_it != ')') {
                rawBacktrace_it++;
            }
            if (*rawBacktrace_it == ':') {
                const char *linenumber = rawBacktrace_it + 1;
                *rawBacktrace_it = '\0';
                while (*rawBacktrace_it != ')') {
                    rawBacktrace_it++;
                }
                *rawBacktrace_it = '\0';
                rawBacktrace_it++;
                stackFrame.linenumber = atoi(linenumber);
            }
            else {
                stackFrame.filename = NULL;
                while (*rawBacktrace_it != '\n') {
                    rawBacktrace_it++;
                }
            }
            while (*rawBacktrace_it == '\n' || *rawBacktrace_it == ' ') {
                    rawBacktrace_it++;
            }
            parsedBacktrace.push_back(stackFrame); /* module */
        }
        return parsedBacktrace;
    }
};

std::vector<RawStackFrame> get_backtrace() {
    static DalvikBacktraceProvider backtraceProvider;
    return backtraceProvider.parseBacktrace(backtraceProvider.getBacktrace());
}

/* end ANDROID */
#elif defined __linux__

#include <execinfo.h>
#include <string.h>
#include <stdlib.h>
#include <map>
#include <vector>
#include <stdio.h>

namespace trace {

#define BT_DEPTH 10

class GlibcBacktraceProvider {
private:
    std::map<void*, RawStackFrame*> cache;
    /*
     * Backtrace being returned by glibc backtrace() contains stack frames
     * belonging to apitrace wrapper module. We count the number of apitrace
     * functions on the stack to avoid recording these frames.
     */
    int numOfNestedFunctions;
    Id nextFrameId;
private:
/*
 * Parse a stack frame, expecting:
 * /lib/libc.so.6.1(__libc_start_main+0x50308) [0x2000000000097630]
 * or
 * /lib/libc.so.6.1(+0x50308) [0x2000000000097630]
 * or
 * /lib/libc.so.6.1() [0x2000000000097630]
 */
    RawStackFrame* parseFrame(void* frame, char* frame_symbol) {
        if (cache.find(frame) == cache.end()) {
            char* frame_symbol_copy = new char[strlen(frame_symbol) + 1];
            strcpy(frame_symbol_copy, frame_symbol);
            RawStackFrame* parsedFrame = new RawStackFrame;
            parsedFrame->id = nextFrameId++;
            char* frame_it = frame_symbol_copy;
            parsedFrame->module = frame_it;
            char* offset = NULL;
            while (true) {
                switch (*frame_it) {
                case '(':
                    *frame_it = '\0';
                    frame_it++;
                    if (*frame_it != ')' && *frame_it != '+') {
                        parsedFrame->function = frame_it;
                        while (*frame_it != '+' && *frame_it != ')') {
                            frame_it++;
                        }
                        *frame_it = '\0';
                        frame_it++;
                    }
                    break;
                case '[':
                    *frame_it = '\0';
                    frame_it++;
                    offset = frame_it;
                    break;
                case ']':
                    *frame_it = '\0';
                    sscanf(offset, "%llx", &parsedFrame->offset);
                    cache[frame] = parsedFrame;
                    return parsedFrame;
                case '\0':
                    cache[frame] = NULL;
                    delete[] frame_symbol_copy;
                    delete[] parsedFrame;
                    return NULL;
                default:
                    frame_it++;
                }
            }
        }
        else {
            return cache[frame];
        }
    }
public:
    GlibcBacktraceProvider() :
      numOfNestedFunctions(0),
      nextFrameId(0)
    {}

    std::vector<RawStackFrame> getParsedBacktrace() {
        std::vector<RawStackFrame> parsedBacktrace;
        void *array[numOfNestedFunctions + BT_DEPTH];
        size_t size;
        char **strings;
        size_t i;
        const char* firstModule;
        size = backtrace(array, numOfNestedFunctions + BT_DEPTH);
        strings = backtrace_symbols(array, size);
        for (i = numOfNestedFunctions; i < size; i++) {
            RawStackFrame* parsedFrame = parseFrame(array[i], strings[i]);
            if (numOfNestedFunctions == 0) {
                if (i == 0) {
                    firstModule = parsedFrame->module;
                }
                else {
                    if (strcmp(firstModule, parsedFrame->module)) {
                        numOfNestedFunctions = i;
                        free(strings);
                        parsedBacktrace = getParsedBacktrace();
                        numOfNestedFunctions--;
                        return parsedBacktrace;
                    }
                }
            } else {
                if (parsedFrame != NULL) {
                    parsedBacktrace.push_back(*parsedFrame);
                }
            }
        }
        free(strings);
        return parsedBacktrace;
    }
};

std::vector<RawStackFrame> get_backtrace() {
    static GlibcBacktraceProvider backtraceProvider;
    return backtraceProvider.getParsedBacktrace();
}

#endif /* LINUX */

} /* namespace trace */

#endif /* ANDROID or LINUX */
<commit_msg>Implement libbacktrace provider<commit_after>/**************************************************************************
 *
 * Copyright 2013 Samsung
 * Contributed by Eugene Velesevich
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

/*
 *  Wrapper for platform-specific code for obtaining symbolic backtraces
 *  on Android and Linux
 */

#include "trace_backtrace.hpp"

#if defined(ANDROID) or defined(__linux__)

#include <set>
#include "os.hpp"

namespace trace {

/*
 * Pascal string (with zero terminator optionally omitted)
 * This is a helper class for storing a set of exact strings or prefixes
 * to match a zero-terminated string against later.
 * Two zero-terminated pstrings compare equal iff they are the same.
 * Otherwise, they compare equal iff one is a prefix of the other
 * (a zero-terminated pstring cannot be a prefix)
 */

struct pstring {
    const char* s;
    int n;
    pstring(const char* s, int n)
    {
        this->s = s;
        this->n = n;
    }
    bool operator<(const pstring q2) const
    {
        return memcmp(s, q2.s, n < q2.n? n : q2.n) < 0;
    }
};

class StringPrefixes {
private:
    std::set<pstring> pset;

    void addPrefix(char* startbuf, int n) {
        std::set<pstring>::iterator elem = pset.find(pstring(startbuf, n));
        bool replace = elem != pset.end() && n < elem->n;
        if (replace) {
            pset.erase(elem);
        }
        if (replace || elem == pset.end()) {
            pset.insert(pstring(startbuf, n));
        }
    }
public:
    StringPrefixes();

    bool contain(const char* s) {
        return pset.find(pstring(s, strlen(s) + 1)) != pset.end();
    }
};

StringPrefixes::StringPrefixes() {
    char *list = getenv("APITRACE_BACKTRACE");
    if (!list)
        return;
    for (char *t = strdup(list); ; t = NULL) {
        char *tok = strtok(t, " \t\r\n");
        if (!tok)
            break;
        if (tok[0] == '#')
            continue;
        if (tok[strlen(tok) - 1] == '*')
            addPrefix(tok, strlen(tok) - 1);
        else
            addPrefix(tok, strlen(tok) + 1);
    }
}

bool backtrace_is_needed(const char* fname) {
    static StringPrefixes backtraceFunctionNamePrefixes;
    return backtraceFunctionNamePrefixes.contain(fname);
}

} /* namespace trace */

#ifdef ANDROID

#include <dlfcn.h>
#include "os.hpp"
#include <vector>

namespace trace {

/* The following two declarations are copied from Android sources */

enum DebugTargetKind {
    kDebugTargetUnknown = 0,
    kDebugTargetLog,
    kDebugTargetFile,
};

struct DebugOutputTarget {
    DebugTargetKind which;

    union {
        struct {
            int priority;
            const char* tag;
        } log;
        struct {
            FILE* fp;
        } file;
    } data;
};

#define THREAD_SELF_NAME "_Z13dvmThreadSelfv"
#define CREATE_DEBUG_TARGET_NAME "_Z25dvmCreateFileOutputTargetP17DebugOutputTargetP7__sFILE"
#define DUMP_BACKTRACE_NAME "_Z18dvmDumpThreadStackPK17DebugOutputTargetP6Thread"

class DalvikBacktraceProvider {
private:
    bool errorOccured;
    void* (*threadself)(void);
    FILE* streamInMemory;
    char* buf;
    size_t bufSize;
    void (*dumpBacktrace)(const DebugOutputTarget*, void*);
    DebugOutputTarget debugTarget;
    Id nextFrameId;
public:
    DalvikBacktraceProvider() {
        nextFrameId = 0;
        FILE* (*open_memstream_exp)(char**, size_t*);
        void (*createDebugTarget)(DebugOutputTarget*, FILE*);
        void* handle = dlopen("/system/lib/libdvm.so", 0);
        errorOccured = true;
        if (!handle) {
            os::log("dlopen failed\n");
            return;
        }
        threadself = (void* (*)())dlsym(handle, THREAD_SELF_NAME);
        if (threadself == NULL) {
            os::log("dlsym ThreadSelf failed\n");
            return;
        }
        createDebugTarget = (void (*)(DebugOutputTarget*, FILE*))dlsym(handle, CREATE_DEBUG_TARGET_NAME);
        if (createDebugTarget == NULL) {
            os::log("dlsym CreateFileOutput failed\n");
            return;
        }
        dumpBacktrace = (void (*)(const DebugOutputTarget*, void*))dlsym(handle, DUMP_BACKTRACE_NAME);
        if (dumpBacktrace == NULL) {
            os::log("dlsym DumpThreadStack failed\n");
            return;
        }
        void* handle2 = dlopen("/system/lib/libcutils.so", 0);
        if (!handle2) {
            os::log("dlopen failed\n");
            return;
        }
        open_memstream_exp = (FILE* (*)(char**, size_t*))dlsym(handle2, "open_memstream");
        if (open_memstream_exp == NULL) {
            os::log("dlsym open_memstream failed\n");
            return;
        }
        streamInMemory = open_memstream_exp(&buf, &bufSize);
        if (streamInMemory == NULL) {
            os::log("open_memstream failed\n");
            return;
        }
        createDebugTarget(&debugTarget, streamInMemory);
        errorOccured = false;
    }

    inline char* getBacktrace() {
        if (errorOccured) {
            return NULL;
        }
        rewind(streamInMemory);
        dumpBacktrace(&debugTarget, threadself());
        fflush(streamInMemory);
        return buf;
    }
/*
 * Parse a stack frame, expecting:
 * "  at android.view.HardwareRenderer$GlRenderer.initializeEgl(HardwareRenderer.java:547)"
 * or
 * "  at android.view.HardwareRenderer$GlRenderer.initializeEgl(Native Method)"
 */
    std::vector<RawStackFrame> parseBacktrace(char *rawBacktrace) {
        std::vector<RawStackFrame> parsedBacktrace;
        char* rawBacktrace_it = rawBacktrace;
        while (*rawBacktrace_it != '\0') {
            RawStackFrame stackFrame;
            // TODO: Keep a cache of stack frames
            stackFrame.id = nextFrameId++;
            /* skip leading space */
            while (*rawBacktrace_it == ' ') {
                rawBacktrace_it++;
            }
            /* Skip "at " */
            rawBacktrace_it += 3;
            stackFrame.function = rawBacktrace_it;
            while (*rawBacktrace_it != '(') {
                rawBacktrace_it++;
            }
            *rawBacktrace_it = '\0';
            stackFrame.filename = rawBacktrace_it + 1;
            while (*rawBacktrace_it != ':' && *rawBacktrace_it != ')') {
                rawBacktrace_it++;
            }
            if (*rawBacktrace_it == ':') {
                const char *linenumber = rawBacktrace_it + 1;
                *rawBacktrace_it = '\0';
                while (*rawBacktrace_it != ')') {
                    rawBacktrace_it++;
                }
                *rawBacktrace_it = '\0';
                rawBacktrace_it++;
                stackFrame.linenumber = atoi(linenumber);
            }
            else {
                stackFrame.filename = NULL;
                while (*rawBacktrace_it != '\n') {
                    rawBacktrace_it++;
                }
            }
            while (*rawBacktrace_it == '\n' || *rawBacktrace_it == ' ') {
                    rawBacktrace_it++;
            }
            parsedBacktrace.push_back(stackFrame); /* module */
        }
        return parsedBacktrace;
    }
};

std::vector<RawStackFrame> get_backtrace() {
    static DalvikBacktraceProvider backtraceProvider;
    return backtraceProvider.parseBacktrace(backtraceProvider.getBacktrace());
}

/* end ANDROID */
#elif defined __linux__

#include <stdint.h>
#include <dlfcn.h>
#include <execinfo.h>
#include <string.h>
#include <stdlib.h>
#include <map>
#include <vector>
#include <stdio.h>

#include "backtrace.h"

namespace trace {

#define BT_DEPTH 10

class libbacktraceProvider {
    struct backtrace_state *state;
    int skipFrames;
    Id nextFrameId;
    std::map<uintptr_t, std::vector<RawStackFrame> > cache;
    std::vector<RawStackFrame> *current, *current_frames;
    RawStackFrame *current_frame;

    static void bt_err_callback(void *vdata, const char *msg, int errnum)
    {
        if (errnum == -1)
            return;// no debug/sym info
        else if (errnum)
            os::log("libbacktrace: %s: %s\n", msg, strerror(errnum));
        else
            os::log("libbacktrace: %s\n", msg);
    }

    static int bt_countskip(void *vdata, uintptr_t pc)
    {
        libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
        Dl_info info1, info2;
        if (!dladdr((void*)bt_countskip, &info2)) {
            os::log("dladdr failed, cannot cull stack traces\n");
            return 1;
        }
        if (!dladdr((void*)pc, &info1))
            return 1;
        if (info1.dli_fbase != info2.dli_fbase)
            return 1;
        this_->skipFrames++;
        return 0;
    }

    static int bt_full_callback(void *vdata, uintptr_t pc,
                                 const char *file, int line, const char *func)
    {
        libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
        RawStackFrame frame = *this_->current_frame;
        frame.id = this_->nextFrameId++;
        frame.filename = file;
        frame.linenumber = line;
        if (func)
            frame.function = func;
        this_->current_frames->push_back(frame);
        return 0;
    }

    static int bt_callback(void *vdata, uintptr_t pc)
    {
        libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
        std::vector<RawStackFrame> &frames = this_->cache[pc];
        if (!frames.size()) {
            RawStackFrame frame;
            Dl_info info = {0};
            dladdr((void*)pc, &info);
            frame.module = info.dli_fname;
            frame.function = info.dli_sname;
            frame.offset = info.dli_saddr ? pc - (uintptr_t)info.dli_saddr
                                          : pc - (uintptr_t)info.dli_fbase;
            this_->current_frame = &frame;
            this_->current_frames = &frames;
            backtrace_pcinfo(this_->state, pc, bt_full_callback, bt_err_callback, vdata);
            if (!frames.size()) {
                frame.id = this_->nextFrameId++;
                frames.push_back(frame);
	    }
        }
        this_->current->insert(this_->current->end(), frames.begin(), frames.end());
        return this_->current->size() >= BT_DEPTH;
    }

public:
    libbacktraceProvider():
        state(backtrace_create_state(NULL, 0, bt_err_callback, NULL))
    {
        backtrace_simple(state, 0, bt_countskip, bt_err_callback, this);
    }

    std::vector<RawStackFrame> getParsedBacktrace()
    {
        std::vector<RawStackFrame> parsedBacktrace;
        current = &parsedBacktrace;
        backtrace_simple(state, skipFrames, bt_callback, bt_err_callback, this);
        return parsedBacktrace;
    }
};

class GlibcBacktraceProvider {
private:
    std::map<void*, RawStackFrame*> cache;
    /*
     * Backtrace being returned by glibc backtrace() contains stack frames
     * belonging to apitrace wrapper module. We count the number of apitrace
     * functions on the stack to avoid recording these frames.
     */
    int numOfNestedFunctions;
    Id nextFrameId;
private:
/*
 * Parse a stack frame, expecting:
 * /lib/libc.so.6.1(__libc_start_main+0x50308) [0x2000000000097630]
 * or
 * /lib/libc.so.6.1(+0x50308) [0x2000000000097630]
 * or
 * /lib/libc.so.6.1() [0x2000000000097630]
 */
    RawStackFrame* parseFrame(void* frame, char* frame_symbol) {
        if (cache.find(frame) == cache.end()) {
            char* frame_symbol_copy = new char[strlen(frame_symbol) + 1];
            strcpy(frame_symbol_copy, frame_symbol);
            RawStackFrame* parsedFrame = new RawStackFrame;
            parsedFrame->id = nextFrameId++;
            char* frame_it = frame_symbol_copy;
            parsedFrame->module = frame_it;
            char* offset = NULL;
            while (true) {
                switch (*frame_it) {
                case '(':
                    *frame_it = '\0';
                    frame_it++;
                    if (*frame_it != ')' && *frame_it != '+') {
                        parsedFrame->function = frame_it;
                        while (*frame_it != '+' && *frame_it != ')') {
                            frame_it++;
                        }
                        *frame_it = '\0';
                        frame_it++;
                    }
                    break;
                case '[':
                    *frame_it = '\0';
                    frame_it++;
                    offset = frame_it;
                    break;
                case ']':
                    *frame_it = '\0';
                    sscanf(offset, "%llx", &parsedFrame->offset);
                    cache[frame] = parsedFrame;
                    return parsedFrame;
                case '\0':
                    cache[frame] = NULL;
                    delete[] frame_symbol_copy;
                    delete[] parsedFrame;
                    return NULL;
                default:
                    frame_it++;
                }
            }
        }
        else {
            return cache[frame];
        }
    }
public:
    GlibcBacktraceProvider() :
      numOfNestedFunctions(0),
      nextFrameId(0)
    {}

    std::vector<RawStackFrame> getParsedBacktrace() {
        std::vector<RawStackFrame> parsedBacktrace;
        void *array[numOfNestedFunctions + BT_DEPTH];
        size_t size;
        char **strings;
        size_t i;
        const char* firstModule;
        size = backtrace(array, numOfNestedFunctions + BT_DEPTH);
        strings = backtrace_symbols(array, size);
        for (i = numOfNestedFunctions; i < size; i++) {
            RawStackFrame* parsedFrame = parseFrame(array[i], strings[i]);
            if (numOfNestedFunctions == 0) {
                if (i == 0) {
                    firstModule = parsedFrame->module;
                }
                else {
                    if (strcmp(firstModule, parsedFrame->module)) {
                        numOfNestedFunctions = i;
                        free(strings);
                        parsedBacktrace = getParsedBacktrace();
                        numOfNestedFunctions--;
                        return parsedBacktrace;
                    }
                }
            } else {
                if (parsedFrame != NULL) {
                    parsedBacktrace.push_back(*parsedFrame);
                }
            }
        }
        free(strings);
        return parsedBacktrace;
    }
};

std::vector<RawStackFrame> get_backtrace() {
    static GlibcBacktraceProvider backtraceProvider;
    return backtraceProvider.getParsedBacktrace();
}

#endif /* LINUX */

} /* namespace trace */

#endif /* ANDROID or LINUX */
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/build/linker/gensyms.C $                                  */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2013,2014                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <map>
#include <string>
#include <stdint.h>
#include <cstring>
#include <endian.h>
#include <assert.h>
#include <limits.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

#ifndef be64toh
    #include <byteswap.h>
    #if __BYTE_ORDER == __LITTLE_ENDIAN
        #define be64toh(x) __bswap_64(x)
    #else
        #define be64toh(x) (x)
    #endif
#endif

using namespace std;

/** Print tool usage */
void print_usage();

/** Prepend to a path the img/ subdirectory.
 *
 *  @param[in,out] io_path - The path to modify / prepend to.
 */
void add_image_subdir(string& io_path);

/** Parse the image.modinfo file.
 *
 *  @param[in] i_image - The path to the image to parse the corresponding
 *                       modinfo.
 */
void parse_modinfo_file(const string& i_image);

/** Read the symbols from a module.
 *
 *  @param[in] pair<string, uint64_t>* - Pair of <Path of module, offset >.
 *
 *  Parameters are passed as a (void*) to allow this function to be started
 *  as a thread.
 *
 *  @return Unused.
 */
void* read_module_symbols(void*);

    /** Module information parsed from modinfo.  <Module, Offset> */
vector<pair<string, uint64_t> > g_modules;

    /** Name / path of the base image. */
string g_imageName;
    /** Name / path of the extended image. */
string g_extImageName;
    /** Pointer to the mmap of the base image. */
const char* g_imageFile;
    /** Size of the base image file. */
size_t g_imageFileSize;
    /** Pointer to the mmap of the extended image. */
const char* g_extImageFile;
    /** Size of the extended image file. */
size_t g_extImageFileSize;
    /** Offset (in memory) that the extended image is to be loaded at. */
uint64_t g_extImageOffset = ULONG_MAX;

    /** Cached value of the CROSS_PREFIX environment variable, used to
     *  call binutils tools. */
char* g_crossPrefix = NULL;

    /** Resulting symbol addresses and names.
     *
     *  This is a multimap because there are some symbol addresses with
     *  multiple names.  Ex. the data_start_address often collides with
     *  a global symbol in the data section.
     */
multimap<uint64_t, string> g_symbols;
    /** Mutex to protect symbol map. */
pthread_mutex_t g_symbolMutex = PTHREAD_MUTEX_INITIALIZER;

int main(int argc, char** argv)
{
    // Allow one argument (base image) or three arguments (base, extend, offset)
    if ((argc != 2) && (argc != 4))
    {
        print_usage();
    }

    // Get base image name.
    g_imageName = argv[1];
    add_image_subdir(g_imageName);

    // Get extended image name.
    if (argc > 3)
    {
        g_extImageName = argv[2];
        add_image_subdir(g_extImageName);

        // Read extended image offset from options.
        if (1 != sscanf(argv[3], "%lx", &g_extImageOffset))
        {
            print_usage();
        }
    }

    // Open base image.
    int base_fd = open(g_imageName.c_str(), O_RDONLY);
    if (-1 == base_fd)
    {
        printf("Failed to open image file: %s.\n", g_imageName.c_str());
        exit(-1);
    }
    struct stat base_stat;
    if (0 != fstat(base_fd, &base_stat))
    {
        printf("Failed to stat image file: %s.\n", g_imageName.c_str());
        exit(-1);
    }
    g_imageFileSize = base_stat.st_size;
    g_imageFile = (const char*) mmap(NULL, base_stat.st_size,
                                     PROT_READ, MAP_PRIVATE,
                                     base_fd, 0);

    // Open extended image.
    if (string() != g_extImageName.c_str())
    {
        int ext_fd = open(g_extImageName.c_str(), O_RDONLY);
        if (-1 == ext_fd)
        {
            printf("Failed to open image file: %s.\n", g_extImageName.c_str());
            exit(-1);
        }
        struct stat ext_stat;
        if (0 != fstat(ext_fd, &ext_stat))
        {
            printf("Failed to stat image file: %s.\n", g_extImageName.c_str());
            exit(-1);
        }
        g_extImageFileSize = ext_stat.st_size;
        g_extImageFile = (const char*) mmap(NULL, ext_stat.st_size,
                                            PROT_READ, MAP_PRIVATE,
                                            ext_fd, 0);
    }

    // Read CROSS_PREFIX environment variable.
    g_crossPrefix = getenv("CROSS_PREFIX");
    if (NULL == g_crossPrefix)
    {
        printf("Environment variable CROSS_PREFIX not set.\n");
        exit(-1);
    }
    g_crossPrefix = strdup(g_crossPrefix);

    // Parse modinfo file for base image.
    parse_modinfo_file(g_imageName);

    // Create threads for each ELF object in the image(s) to get their symbol
    // information.
    vector<pthread_t*> threads;
    for(vector<pair<string, uint64_t> >::const_iterator i = g_modules.begin();
        i != g_modules.end(); ++i)
    {
        const string& m = i->first;
        // Filter out non-ELF files by filename.
        if (strstr(m.c_str(), ".o") || strstr(m.c_str(), ".elf") ||
            strstr(m.c_str(), ".so"))
        {
            pthread_t* thread = new pthread_t;
            pthread_create(thread, NULL, read_module_symbols,
                           new pair<string,uint64_t>(*i));
            threads.push_back(thread);
        }
    }

    // Wait for all threads to finish.
    for(vector<pthread_t*>::const_iterator i = threads.begin();
        i != threads.end(); ++i)
    {
        pthread_join(*(*i), NULL);
    }

    // Output (in order) each symbol information.
    for (multimap<uint64_t, string>::const_iterator i = g_symbols.begin();
         i != g_symbols.end(); ++i)
    {
        printf("%s", i->second.c_str());
    }

    return 0;
}

void print_usage()
{
    printf("gensyms <image> [<extimage> <extoffset>]\n");
    exit(-1);
}

void add_image_subdir(string& io_path)
{
    // Prepend ./img if the path to the image directory is not already part
    // of the path.
    if (string::npos == io_path.find("img"))
    {
        io_path.insert(0, "./img/");
    }
}

void parse_modinfo_file(const string& i_image)
{
    // Open modinfo file.
    string modinfo_name = i_image + ".modinfo";
    FILE* modinfo_file = fopen(modinfo_name.c_str(), "r");
    if (NULL == modinfo_file)
    {
        printf("Unable to open modinfo file.\n");
        exit(-1);
    }

    // Parse one line at a time.
    char line[1024];
    do
    {
        // fgets returns NULL when no additional lines are present, break.
        if (NULL == fgets(line, 1024, modinfo_file)) break;

        // Lines should be formatted: "object,offset\n"

        // Skip lines without a comma.
        char* comma = strchr(line, ',');
        if (NULL == comma) continue;

        // Extract module name (everything before comma).
        string mod_name(line, comma - line);

        // Parse module offset (hex integer after comma).
        uint64_t mod_addr;
        if (1 != sscanf(comma+1, "0x%lx", &mod_addr)) continue;

        // Add to the module list.
        g_modules.push_back(make_pair(mod_name, mod_addr));

    } while(1);
}

void* read_module_symbols(void* input)
{
    // Get module name and offset from input parameter.
    pair<string, uint64_t>* mod_info =
        reinterpret_cast<pair<string,uint64_t>*>(input);
    const string& module = mod_info->first;
    uint64_t addr = mod_info->second;

    // Determine the full path to the module based on the base image path.
    // Assumes they are in the same subdirectory.
    string module_path = g_imageName.substr(0, g_imageName.rfind('/') + 1) +
                         module;

    // Create the 'objdump' command for finding all the symbols and start as
    // a sub-process.
    string command = string(g_crossPrefix) + string("objdump --syms -C ") +
                     module_path;
    FILE* pipe = popen(command.c_str(), "r");
    if (NULL == pipe) return NULL;

    // Local symbol map (to reduce contention on the global symbol map).
    //   No need to use the overhead of a map because we don't care about
    //   order at this point.
    vector<pair<uint64_t, string> > l_symbols;

    // Parse each line of the 'objdump' output.
    char line[1024];
    do
    {
        if (NULL == fgets(line, 1024, pipe)) break;

        // Skip absolute values (ex. constants) and undefined symbols.
        if (strstr(line, "*ABS*") || strstr(line, "*UND*")) continue;
        // Skip section symbols (marked by 'd' in the 22nd column).
        if ('d' == line[22]) continue;

        // First part of an objdump line is the symbol address, parse that.
        uint64_t line_address;
        if (1 != sscanf(line, "%16lx", &line_address)) continue;
        line_address += addr;

        // Determine if the symbol is a function and if it is in the .rodata
        // section.  Symbols in the .rodata section have a slightly longer
        // line than those in the .text/.data sections (by 2 characters).
        bool is_function = ('F' == line[23]);
        size_t rodata = (NULL != strstr(line, ".rodata")) ? 2 : 0;

        // Parse the symbol size.
        uint64_t symbol_size;
        if (1 != sscanf(&line[32+rodata], "%lx", &symbol_size)) continue;

        // Parse the function name.
        string function = &line[48+rodata];
        function.resize(function.length() - 1); // remove the newline.

        // Function have two addresses: TOC entry and code address.  Objdump
        // gives the TOC entry, so we need to read the file itself to determine
        // the code address.  The first part of the TOC entry is the code
        // address.
        uint64_t code_addr = 0;
        if (is_function)
        {
            // Module is in the extended image, read from it.
            if (line_address > g_extImageOffset)
            {
                // Read code address.
                assert((line_address - g_extImageOffset) < g_extImageFileSize);
                memcpy(&code_addr,
                       &g_extImageFile[line_address - g_extImageOffset], 8);
            }
            // Module is in the base image.
            else
            {
                // Read code address.
                assert(line_address < g_imageFileSize);
                memcpy(&code_addr, &g_imageFile[line_address], 8);
            }
            // Fix up the endianness.
            code_addr = be64toh(code_addr);

            std::swap(code_addr, line_address);
        }

        // Print all of this into a new line and add to the symbol map.
        sprintf(line, "%c,%08lx,%08lx,%08lx,%s\n",
            is_function ? 'F' : 'V',
            line_address, code_addr, symbol_size,
            function.c_str());

        l_symbols.push_back(make_pair(line_address, line));

    } while(1);

    // Close subprocess (done).
    pclose(pipe);

    // Copy our local symbol list all at once into the global symbol list.
    pthread_mutex_lock(&g_symbolMutex);
    g_symbols.insert(l_symbols.begin(), l_symbols.end());
    pthread_mutex_unlock(&g_symbolMutex);

    return NULL;
}
<commit_msg>linker/gensyms: Check length of line read from objdump<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/build/linker/gensyms.C $                                  */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2013,2015                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <map>
#include <string>
#include <stdint.h>
#include <cstring>
#include <endian.h>
#include <assert.h>
#include <limits.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

#ifndef be64toh
    #include <byteswap.h>
    #if __BYTE_ORDER == __LITTLE_ENDIAN
        #define be64toh(x) __bswap_64(x)
    #else
        #define be64toh(x) (x)
    #endif
#endif

using namespace std;

/** Print tool usage */
void print_usage();

/** Prepend to a path the img/ subdirectory.
 *
 *  @param[in,out] io_path - The path to modify / prepend to.
 */
void add_image_subdir(string& io_path);

/** Parse the image.modinfo file.
 *
 *  @param[in] i_image - The path to the image to parse the corresponding
 *                       modinfo.
 */
void parse_modinfo_file(const string& i_image);

/** Read the symbols from a module.
 *
 *  @param[in] pair<string, uint64_t>* - Pair of <Path of module, offset >.
 *
 *  Parameters are passed as a (void*) to allow this function to be started
 *  as a thread.
 *
 *  @return Unused.
 */
void* read_module_symbols(void*);

    /** Module information parsed from modinfo.  <Module, Offset> */
vector<pair<string, uint64_t> > g_modules;

    /** Name / path of the base image. */
string g_imageName;
    /** Name / path of the extended image. */
string g_extImageName;
    /** Pointer to the mmap of the base image. */
const char* g_imageFile;
    /** Size of the base image file. */
size_t g_imageFileSize;
    /** Pointer to the mmap of the extended image. */
const char* g_extImageFile;
    /** Size of the extended image file. */
size_t g_extImageFileSize;
    /** Offset (in memory) that the extended image is to be loaded at. */
uint64_t g_extImageOffset = ULONG_MAX;

    /** Cached value of the CROSS_PREFIX environment variable, used to
     *  call binutils tools. */
char* g_crossPrefix = NULL;

    /** Resulting symbol addresses and names.
     *
     *  This is a multimap because there are some symbol addresses with
     *  multiple names.  Ex. the data_start_address often collides with
     *  a global symbol in the data section.
     */
multimap<uint64_t, string> g_symbols;
    /** Mutex to protect symbol map. */
pthread_mutex_t g_symbolMutex = PTHREAD_MUTEX_INITIALIZER;

int main(int argc, char** argv)
{
    // Allow one argument (base image) or three arguments (base, extend, offset)
    if ((argc != 2) && (argc != 4))
    {
        print_usage();
    }

    // Get base image name.
    g_imageName = argv[1];
    add_image_subdir(g_imageName);

    // Get extended image name.
    if (argc > 3)
    {
        g_extImageName = argv[2];
        add_image_subdir(g_extImageName);

        // Read extended image offset from options.
        if (1 != sscanf(argv[3], "%lx", &g_extImageOffset))
        {
            print_usage();
        }
    }

    // Open base image.
    int base_fd = open(g_imageName.c_str(), O_RDONLY);
    if (-1 == base_fd)
    {
        printf("Failed to open image file: %s.\n", g_imageName.c_str());
        exit(-1);
    }
    struct stat base_stat;
    if (0 != fstat(base_fd, &base_stat))
    {
        printf("Failed to stat image file: %s.\n", g_imageName.c_str());
        exit(-1);
    }
    g_imageFileSize = base_stat.st_size;
    g_imageFile = (const char*) mmap(NULL, base_stat.st_size,
                                     PROT_READ, MAP_PRIVATE,
                                     base_fd, 0);

    // Open extended image.
    if (string() != g_extImageName.c_str())
    {
        int ext_fd = open(g_extImageName.c_str(), O_RDONLY);
        if (-1 == ext_fd)
        {
            printf("Failed to open image file: %s.\n", g_extImageName.c_str());
            exit(-1);
        }
        struct stat ext_stat;
        if (0 != fstat(ext_fd, &ext_stat))
        {
            printf("Failed to stat image file: %s.\n", g_extImageName.c_str());
            exit(-1);
        }
        g_extImageFileSize = ext_stat.st_size;
        g_extImageFile = (const char*) mmap(NULL, ext_stat.st_size,
                                            PROT_READ, MAP_PRIVATE,
                                            ext_fd, 0);
    }

    // Read CROSS_PREFIX environment variable.
    g_crossPrefix = getenv("CROSS_PREFIX");
    if (NULL == g_crossPrefix)
    {
        printf("Environment variable CROSS_PREFIX not set.\n");
        exit(-1);
    }
    g_crossPrefix = strdup(g_crossPrefix);

    // Parse modinfo file for base image.
    parse_modinfo_file(g_imageName);

    // Create threads for each ELF object in the image(s) to get their symbol
    // information.
    vector<pthread_t*> threads;
    for(vector<pair<string, uint64_t> >::const_iterator i = g_modules.begin();
        i != g_modules.end(); ++i)
    {
        const string& m = i->first;
        // Filter out non-ELF files by filename.
        if (strstr(m.c_str(), ".o") || strstr(m.c_str(), ".elf") ||
            strstr(m.c_str(), ".so"))
        {
            pthread_t* thread = new pthread_t;
            pthread_create(thread, NULL, read_module_symbols,
                           new pair<string,uint64_t>(*i));
            threads.push_back(thread);
        }
    }

    // Wait for all threads to finish.
    for(vector<pthread_t*>::const_iterator i = threads.begin();
        i != threads.end(); ++i)
    {
        pthread_join(*(*i), NULL);
    }

    // Output (in order) each symbol information.
    for (multimap<uint64_t, string>::const_iterator i = g_symbols.begin();
         i != g_symbols.end(); ++i)
    {
        printf("%s", i->second.c_str());
    }

    return 0;
}

void print_usage()
{
    printf("gensyms <image> [<extimage> <extoffset>]\n");
    exit(-1);
}

void add_image_subdir(string& io_path)
{
    // Prepend ./img if the path to the image directory is not already part
    // of the path.
    if (string::npos == io_path.find("img"))
    {
        io_path.insert(0, "./img/");
    }
}

void parse_modinfo_file(const string& i_image)
{
    // Open modinfo file.
    string modinfo_name = i_image + ".modinfo";
    FILE* modinfo_file = fopen(modinfo_name.c_str(), "r");
    if (NULL == modinfo_file)
    {
        printf("Unable to open modinfo file.\n");
        exit(-1);
    }

    // Parse one line at a time.
    char line[1024];
    do
    {
        // fgets returns NULL when no additional lines are present, break.
        if (NULL == fgets(line, 1024, modinfo_file)) break;

        // Lines should be formatted: "object,offset\n"

        // Skip lines without a comma.
        char* comma = strchr(line, ',');
        if (NULL == comma) continue;

        // Extract module name (everything before comma).
        string mod_name(line, comma - line);

        // Parse module offset (hex integer after comma).
        uint64_t mod_addr;
        if (1 != sscanf(comma+1, "0x%lx", &mod_addr)) continue;

        // Add to the module list.
        g_modules.push_back(make_pair(mod_name, mod_addr));

    } while(1);
}

void* read_module_symbols(void* input)
{
    // Get module name and offset from input parameter.
    pair<string, uint64_t>* mod_info =
        reinterpret_cast<pair<string,uint64_t>*>(input);
    const string& module = mod_info->first;
    uint64_t addr = mod_info->second;

    // Determine the full path to the module based on the base image path.
    // Assumes they are in the same subdirectory.
    string module_path = g_imageName.substr(0, g_imageName.rfind('/') + 1) +
                         module;

    // Create the 'objdump' command for finding all the symbols and start as
    // a sub-process.
    string command = string(g_crossPrefix) + string("objdump --syms -C ") +
                     module_path;
    FILE* pipe = popen(command.c_str(), "r");
    if (NULL == pipe) return NULL;

    // Local symbol map (to reduce contention on the global symbol map).
    //   No need to use the overhead of a map because we don't care about
    //   order at this point.
    vector<pair<uint64_t, string> > l_symbols;

    // Parse each line of the 'objdump' output.
    char line[1024];
    do
    {
        if (NULL == fgets(line, 1024, pipe)) break;

        size_t linelen = strlen(line);

        // Skip absolute values (ex. constants) and undefined symbols.
        if (strstr(line, "*ABS*") || strstr(line, "*UND*")) continue;
        // Skip section symbols (marked by 'd' in the 22nd column).
        if (linelen > 22 && 'd' == line[22]) continue;

        // First part of an objdump line is the symbol address, parse that.
        uint64_t line_address;
        if (1 != sscanf(line, "%16lx", &line_address)) continue;
        line_address += addr;

        // Determine if the symbol is a function and if it is in the .rodata
        // section.  Symbols in the .rodata section have a slightly longer
        // line than those in the .text/.data sections (by 2 characters).
        bool is_function = (linelen > 23 && 'F' == line[23]);
        size_t rodata = (NULL != strstr(line, ".rodata")) ? 2 : 0;

        // Parse the symbol size.
        uint64_t symbol_size;
        if (linelen > 32+rodata &&
            1 != sscanf(&line[32+rodata], "%lx", &symbol_size)) continue;

        // Parse the function name.
        assert(linelen > 48+rodata);
        string function = &line[48+rodata];
        function.resize(function.length() - 1); // remove the newline.

        // Function have two addresses: TOC entry and code address.  Objdump
        // gives the TOC entry, so we need to read the file itself to determine
        // the code address.  The first part of the TOC entry is the code
        // address.
        uint64_t code_addr = 0;
        if (is_function)
        {
            // Module is in the extended image, read from it.
            if (line_address > g_extImageOffset)
            {
                // Read code address.
                assert((line_address - g_extImageOffset) < g_extImageFileSize);
                memcpy(&code_addr,
                       &g_extImageFile[line_address - g_extImageOffset], 8);
            }
            // Module is in the base image.
            else
            {
                // Read code address.
                assert(line_address < g_imageFileSize);
                memcpy(&code_addr, &g_imageFile[line_address], 8);
            }
            // Fix up the endianness.
            code_addr = be64toh(code_addr);

            std::swap(code_addr, line_address);
        }

        // Print all of this into a new line and add to the symbol map.
        sprintf(line, "%c,%08lx,%08lx,%08lx,%s\n",
            is_function ? 'F' : 'V',
            line_address, code_addr, symbol_size,
            function.c_str());

        l_symbols.push_back(make_pair(line_address, line));

    } while(1);

    // Close subprocess (done).
    pclose(pipe);

    // Copy our local symbol list all at once into the global symbol list.
    pthread_mutex_lock(&g_symbolMutex);
    g_symbols.insert(l_symbols.begin(), l_symbols.end());
    pthread_mutex_unlock(&g_symbolMutex);

    return NULL;
}
<|endoftext|>


<commit_before>#include <fcntl.h>
#include <cstdint>

constexpr size_t ev_buffsz = 512;

#ifdef __linux__
#include "epoll.hpp"
typedef nntpchan::ev::EpollLoop<ev_buffsz> LoopImpl;
#else
#ifdef __FreeBSD__
#include "kqueue.hpp"
typedef nntpchan::ev::KqueueLoop<ev_buffsz> LoopImpl;
#else
#ifdef __netbsd__
typedef nntpchan::ev::KqueueLoop<ev_buffsz> LoopImpl;
#else
#error "unsupported platform"
#endif
#endif
#endif

namespace nntpchan
{
namespace ev
{
bool ev::Loop::BindTCP(const sockaddr *addr, ev::io *handler)
{
  assert(handler->acceptable());
  socklen_t slen;
  switch (addr->sa_family)
  {
  case AF_INET:
    slen = sizeof(sockaddr_in);
    break;
  case AF_INET6:
    slen = sizeof(sockaddr_in6);
    break;
  case AF_UNIX:
    slen = sizeof(sockaddr_un);
    break;
  default:
    return false;
  }
  int fd = socket(addr->sa_family, SOCK_STREAM | SOCK_NONBLOCK, 0);
  if (fd == -1)
  {
    return false;
  }

  if (bind(fd, addr, slen) == -1)
  {
    ::close(fd);
    return false;
  }

  if (listen(fd, 5) == -1)
  {
    ::close(fd);
    return false;
  }

  handler->fd = fd;
  return TrackConn(handler);
}

bool Loop::SetNonBlocking(ev::io *handler)
{
  return fcntl(handler->fd, F_SETFL, fcntl(handler->fd, F_GETFL, 0) | O_NONBLOCK) != -1;
}
}

ev::Loop *NewMainLoop() { return new LoopImpl; }
}<commit_msg>use std::size_t<commit_after>#include <fcntl.h>
#include <cstdint>

constexpr std::size_t ev_buffsz = 512;

#ifdef __linux__
#include "epoll.hpp"
typedef nntpchan::ev::EpollLoop<ev_buffsz> LoopImpl;
#else
#ifdef __FreeBSD__
#include "kqueue.hpp"
typedef nntpchan::ev::KqueueLoop<ev_buffsz> LoopImpl;
#else
#ifdef __netbsd__
typedef nntpchan::ev::KqueueLoop<ev_buffsz> LoopImpl;
#else
#error "unsupported platform"
#endif
#endif
#endif

namespace nntpchan
{
namespace ev
{
bool ev::Loop::BindTCP(const sockaddr *addr, ev::io *handler)
{
  assert(handler->acceptable());
  socklen_t slen;
  switch (addr->sa_family)
  {
  case AF_INET:
    slen = sizeof(sockaddr_in);
    break;
  case AF_INET6:
    slen = sizeof(sockaddr_in6);
    break;
  case AF_UNIX:
    slen = sizeof(sockaddr_un);
    break;
  default:
    return false;
  }
  int fd = socket(addr->sa_family, SOCK_STREAM | SOCK_NONBLOCK, 0);
  if (fd == -1)
  {
    return false;
  }

  if (bind(fd, addr, slen) == -1)
  {
    ::close(fd);
    return false;
  }

  if (listen(fd, 5) == -1)
  {
    ::close(fd);
    return false;
  }

  handler->fd = fd;
  return TrackConn(handler);
}

bool Loop::SetNonBlocking(ev::io *handler)
{
  return fcntl(handler->fd, F_SETFL, fcntl(handler->fd, F_GETFL, 0) | O_NONBLOCK) != -1;
}
}

ev::Loop *NewMainLoop() { return new LoopImpl; }
}<|endoftext|>


<commit_before>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "sharded_hash_map.h"
#include "fixed_size_hash_map.h"
#include "entry_comparator.h"
#include <vespa/vespalib/util/memoryusage.h>

namespace vespalib::datastore {

class ShardedHashMapShardHeld : public GenerationHeldBase
{
    std::unique_ptr<const FixedSizeHashMap> _data;
public:
    ShardedHashMapShardHeld(size_t size, std::unique_ptr<const FixedSizeHashMap> data);
    ~ShardedHashMapShardHeld() override;
};

ShardedHashMapShardHeld::ShardedHashMapShardHeld(size_t size, std::unique_ptr<const FixedSizeHashMap> data)
    : GenerationHeldBase(size),
      _data(std::move(data))
{
}

ShardedHashMapShardHeld::~ShardedHashMapShardHeld() = default;

ShardedHashMap::ShardedHashMap(std::unique_ptr<const EntryComparator> comp)
    : _gen_holder(),
      _maps(),
      _comp(std::move(comp))
{
}

ShardedHashMap::~ShardedHashMap()
{
    _gen_holder.clearHoldLists();
    for (size_t i = 0; i < num_shards; ++i) {
        auto map = _maps[i].load(std::memory_order_relaxed);
        delete map;
    }
}

size_t
ShardedHashMap::get_shard_idx(const EntryComparator& comp, EntryRef key_ref) const
{
    return comp.hash(key_ref) % num_shards;
}

void
ShardedHashMap::alloc_shard(size_t shard_idx)
{
    auto map = _maps[shard_idx].load(std::memory_order_relaxed);
    if (map == nullptr) {
        auto umap = std::make_unique<FixedSizeHashMap>(2u, 3u, num_shards);
        _maps[shard_idx].store(umap.release(), std::memory_order_release);
    } else {
        auto umap = std::make_unique<FixedSizeHashMap>(map->size() * 2 + 2, map->size() * 3 + 3, num_shards, *map, *_comp);
        _maps[shard_idx].store(umap.release(), std::memory_order_release);
        hold_shard(std::unique_ptr<const FixedSizeHashMap>(map));
    }
}

void
ShardedHashMap::hold_shard(std::unique_ptr<const FixedSizeHashMap> map)
{
    auto usage = map->get_memory_usage();
    auto hold = std::make_unique<ShardedHashMapShardHeld>(usage.allocatedBytes(), std::move(map));
    _gen_holder.hold(std::move(hold));
}

ShardedHashMap::KvType&
ShardedHashMap::add(const EntryComparator& comp, EntryRef key_ref, std::function<EntryRef(void)>& insert_entry)
{
    size_t shard_idx = get_shard_idx(comp, key_ref);
    auto map = _maps[shard_idx].load(std::memory_order_relaxed);
    if (map == nullptr || map->full()) {
        alloc_shard(shard_idx);
        map = _maps[shard_idx].load(std::memory_order_relaxed);
    }
    return map->add(comp, key_ref, insert_entry);
}

ShardedHashMap::KvType*
ShardedHashMap::remove(const EntryComparator& comp, EntryRef key_ref)
{
    size_t shard_idx = get_shard_idx(comp, key_ref);
    auto map = _maps[shard_idx].load(std::memory_order_relaxed);
    if (map == nullptr) {
        return nullptr;
    }
    return map->remove(comp, key_ref);
}

ShardedHashMap::KvType*
ShardedHashMap::find(const EntryComparator& comp, EntryRef key_ref)
{
    size_t shard_idx = get_shard_idx(comp, key_ref);
    auto map = _maps[shard_idx].load(std::memory_order_relaxed);
    if (map == nullptr) {
        return nullptr;
    }
    return map->find(comp, key_ref);
}

const ShardedHashMap::KvType*
ShardedHashMap::find(const EntryComparator& comp, EntryRef key_ref) const
{
    size_t shard_idx = get_shard_idx(comp, key_ref);
    auto map = _maps[shard_idx].load(std::memory_order_relaxed);
    if (map == nullptr) {
        return nullptr;
    }
    return map->find(comp, key_ref);
}

void
ShardedHashMap::transfer_hold_lists(generation_t generation)
{
    for (size_t i = 0; i < num_shards; ++i) {
        auto map = _maps[i].load(std::memory_order_relaxed);
        if (map != nullptr) {
            map->transfer_hold_lists(generation);
        }
    }
    _gen_holder.transferHoldLists(generation);
}

void
ShardedHashMap::trim_hold_lists(generation_t first_used)
{
    for (size_t i = 0; i < num_shards; ++i) {
        auto map = _maps[i].load(std::memory_order_relaxed);
        if (map != nullptr) {
            map->trim_hold_lists(first_used);
        }
    }
    _gen_holder.trimHoldLists(first_used);
}

size_t
ShardedHashMap::size() const noexcept
{
    size_t result = 0;
    for (size_t i = 0; i < num_shards; ++i) {
        auto map = _maps[i].load(std::memory_order_relaxed);
        if (map != nullptr) {
            result += map->size();
        }
    }
    return result;
}

MemoryUsage
ShardedHashMap::get_memory_usage() const
{
    MemoryUsage memory_usage(sizeof(ShardedHashMap), sizeof(ShardedHashMap), 0, 0);
    for (size_t i = 0; i < num_shards; ++i) {
        auto map = _maps[i].load(std::memory_order_relaxed);
        if (map != nullptr) {
            memory_usage.merge(map->get_memory_usage());
        }
    }
    size_t gen_holder_held_bytes = _gen_holder.getHeldBytes();
    memory_usage.incAllocatedBytes(gen_holder_held_bytes);
    memory_usage.incAllocatedBytesOnHold(gen_holder_held_bytes);
    return memory_usage;
}

void
ShardedHashMap::foreach_key(std::function<void(EntryRef)> callback) const
{
    for (size_t i = 0; i < num_shards; ++i) {
        auto map = _maps[i].load(std::memory_order_relaxed);
        if (map != nullptr) {
            map->foreach_key(callback);
        }
    }
}

void
ShardedHashMap::move_keys(std::function<EntryRef(EntryRef)> callback)
{
    for (size_t i = 0; i < num_shards; ++i) {
        auto map = _maps[i].load(std::memory_order_relaxed);
        if (map != nullptr) {
            map->move_keys(callback);
        }
    }
}

bool
ShardedHashMap::normalize_values(std::function<EntryRef(EntryRef)> normalize)
{
    bool changed = false;
    for (size_t i = 0; i < num_shards; ++i) {
        auto map = _maps[i].load(std::memory_order_relaxed);
        if (map != nullptr) {
            changed |= map->normalize_values(normalize);
        }
    }
    return changed;
}

}
<commit_msg>Really remove const......<commit_after>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "sharded_hash_map.h"
#include "fixed_size_hash_map.h"
#include "entry_comparator.h"
#include <vespa/vespalib/util/memoryusage.h>

namespace vespalib::datastore {

class ShardedHashMapShardHeld : public GenerationHeldBase
{
    std::unique_ptr<const FixedSizeHashMap> _data;
public:
    ShardedHashMapShardHeld(size_t size, std::unique_ptr<const FixedSizeHashMap> data);
    ~ShardedHashMapShardHeld() override;
};

ShardedHashMapShardHeld::ShardedHashMapShardHeld(size_t size, std::unique_ptr<const FixedSizeHashMap> data)
    : GenerationHeldBase(size),
      _data(std::move(data))
{
}

ShardedHashMapShardHeld::~ShardedHashMapShardHeld() = default;

ShardedHashMap::ShardedHashMap(std::unique_ptr<const EntryComparator> comp)
    : _gen_holder(),
      _maps(),
      _comp(std::move(comp))
{
}

ShardedHashMap::~ShardedHashMap()
{
    _gen_holder.clearHoldLists();
    for (size_t i = 0; i < num_shards; ++i) {
        auto map = _maps[i].load(std::memory_order_relaxed);
        delete map;
    }
}

size_t
ShardedHashMap::get_shard_idx(const EntryComparator& comp, EntryRef key_ref)
{
    return comp.hash(key_ref) % num_shards;
}

void
ShardedHashMap::alloc_shard(size_t shard_idx)
{
    auto map = _maps[shard_idx].load(std::memory_order_relaxed);
    if (map == nullptr) {
        auto umap = std::make_unique<FixedSizeHashMap>(2u, 3u, num_shards);
        _maps[shard_idx].store(umap.release(), std::memory_order_release);
    } else {
        auto umap = std::make_unique<FixedSizeHashMap>(map->size() * 2 + 2, map->size() * 3 + 3, num_shards, *map, *_comp);
        _maps[shard_idx].store(umap.release(), std::memory_order_release);
        hold_shard(std::unique_ptr<const FixedSizeHashMap>(map));
    }
}

void
ShardedHashMap::hold_shard(std::unique_ptr<const FixedSizeHashMap> map)
{
    auto usage = map->get_memory_usage();
    auto hold = std::make_unique<ShardedHashMapShardHeld>(usage.allocatedBytes(), std::move(map));
    _gen_holder.hold(std::move(hold));
}

ShardedHashMap::KvType&
ShardedHashMap::add(const EntryComparator& comp, EntryRef key_ref, std::function<EntryRef(void)>& insert_entry)
{
    size_t shard_idx = get_shard_idx(comp, key_ref);
    auto map = _maps[shard_idx].load(std::memory_order_relaxed);
    if (map == nullptr || map->full()) {
        alloc_shard(shard_idx);
        map = _maps[shard_idx].load(std::memory_order_relaxed);
    }
    return map->add(comp, key_ref, insert_entry);
}

ShardedHashMap::KvType*
ShardedHashMap::remove(const EntryComparator& comp, EntryRef key_ref)
{
    size_t shard_idx = get_shard_idx(comp, key_ref);
    auto map = _maps[shard_idx].load(std::memory_order_relaxed);
    if (map == nullptr) {
        return nullptr;
    }
    return map->remove(comp, key_ref);
}

ShardedHashMap::KvType*
ShardedHashMap::find(const EntryComparator& comp, EntryRef key_ref)
{
    size_t shard_idx = get_shard_idx(comp, key_ref);
    auto map = _maps[shard_idx].load(std::memory_order_relaxed);
    if (map == nullptr) {
        return nullptr;
    }
    return map->find(comp, key_ref);
}

const ShardedHashMap::KvType*
ShardedHashMap::find(const EntryComparator& comp, EntryRef key_ref) const
{
    size_t shard_idx = get_shard_idx(comp, key_ref);
    auto map = _maps[shard_idx].load(std::memory_order_relaxed);
    if (map == nullptr) {
        return nullptr;
    }
    return map->find(comp, key_ref);
}

void
ShardedHashMap::transfer_hold_lists(generation_t generation)
{
    for (size_t i = 0; i < num_shards; ++i) {
        auto map = _maps[i].load(std::memory_order_relaxed);
        if (map != nullptr) {
            map->transfer_hold_lists(generation);
        }
    }
    _gen_holder.transferHoldLists(generation);
}

void
ShardedHashMap::trim_hold_lists(generation_t first_used)
{
    for (size_t i = 0; i < num_shards; ++i) {
        auto map = _maps[i].load(std::memory_order_relaxed);
        if (map != nullptr) {
            map->trim_hold_lists(first_used);
        }
    }
    _gen_holder.trimHoldLists(first_used);
}

size_t
ShardedHashMap::size() const noexcept
{
    size_t result = 0;
    for (size_t i = 0; i < num_shards; ++i) {
        auto map = _maps[i].load(std::memory_order_relaxed);
        if (map != nullptr) {
            result += map->size();
        }
    }
    return result;
}

MemoryUsage
ShardedHashMap::get_memory_usage() const
{
    MemoryUsage memory_usage(sizeof(ShardedHashMap), sizeof(ShardedHashMap), 0, 0);
    for (size_t i = 0; i < num_shards; ++i) {
        auto map = _maps[i].load(std::memory_order_relaxed);
        if (map != nullptr) {
            memory_usage.merge(map->get_memory_usage());
        }
    }
    size_t gen_holder_held_bytes = _gen_holder.getHeldBytes();
    memory_usage.incAllocatedBytes(gen_holder_held_bytes);
    memory_usage.incAllocatedBytesOnHold(gen_holder_held_bytes);
    return memory_usage;
}

void
ShardedHashMap::foreach_key(std::function<void(EntryRef)> callback) const
{
    for (size_t i = 0; i < num_shards; ++i) {
        auto map = _maps[i].load(std::memory_order_relaxed);
        if (map != nullptr) {
            map->foreach_key(callback);
        }
    }
}

void
ShardedHashMap::move_keys(std::function<EntryRef(EntryRef)> callback)
{
    for (size_t i = 0; i < num_shards; ++i) {
        auto map = _maps[i].load(std::memory_order_relaxed);
        if (map != nullptr) {
            map->move_keys(callback);
        }
    }
}

bool
ShardedHashMap::normalize_values(std::function<EntryRef(EntryRef)> normalize)
{
    bool changed = false;
    for (size_t i = 0; i < num_shards; ++i) {
        auto map = _maps[i].load(std::memory_order_relaxed);
        if (map != nullptr) {
            changed |= map->normalize_values(normalize);
        }
    }
    return changed;
}

}
<|endoftext|>


<commit_before>#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include "capture.h"

int main(int argc, char* argv[])
{
  if (argc != 2)
    {
      fprintf(stderr,"Need the full path to xalt_record_pkg => quiting!\n");
      exit(1);
    }

  char* run_uuid = getenv("XALT_RUN_UUID");
  if (! run_uuid)
    exit(0);

  char* record_prgm = argv[1];

  std::string cmd;
  std::string syshost;

  cmd.assign();
  cmd.append(" ");

  cap

  return 0;
}
<commit_msg>add pretend R data to test_record_pkg.C<commit_after>#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include "capture.h"

int main(int argc, char* argv[])
{
  if (argc != 2)
    {
      fprintf(stderr,"Need the full path to the directory for xalt_record_pkg => quiting!\n");
      exit(1);
    }

  char* run_uuid = getenv("XALT_RUN_UUID");
  if (! run_uuid)
    exit(0);

  char* xaltDir = argv[1];

  std::string cmd;
  std::string syshost;

  cmd.assign(xaltDir);
  cmd.append("/libexec/xalt_syshost");

  Vstring v;

  capture(cmd,v);
  std::string syshost = v[0];

  cmd.assign(xaltDir);
  cmd.append("/libexec/xalt_record_pkg -s ");
  cmd.append(syshost);
  cmd.append(" -u ");
  cmd.append(run_uuid);
  cmd.append(" program R");
  cmd.append(" xalt_run_uuid ");
  cmd.append(run_uuid);
  cmd.append(" package_name acme");
  cmd.append(" package_verion 1.0");
  cmd.append(" package_file /A/B/acme/1.0");

  printf("%s\n",cmd.c_str());

  return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "skia/ext/vector_platform_device_skia.h"

#include "skia/ext/bitmap_platform_device.h"
#include "third_party/skia/include/core/SkClipStack.h"
#include "third_party/skia/include/core/SkDraw.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "third_party/skia/include/core/SkScalar.h"

namespace skia {

SkDevice* VectorPlatformDeviceSkiaFactory::newDevice(SkCanvas* noUsed,
                                                     SkBitmap::Config config,
                                                     int width, int height,
                                                     bool isOpaque,
                                                     bool isForLayer) {
  SkASSERT(config == SkBitmap::kARGB_8888_Config);
  SkMatrix initialTransform;
  initialTransform.reset();
  if (isForLayer) {
    initialTransform.setTranslate(0, height);
    initialTransform.preScale(1, -1);
  }
  return new VectorPlatformDeviceSkia(width, height, initialTransform);
}

static inline SkBitmap makeABitmap(int width, int height) {
  SkBitmap bitmap;
  bitmap.setConfig(SkBitmap::kNo_Config, width, height);
  return bitmap;
}

VectorPlatformDeviceSkia::VectorPlatformDeviceSkia(
    int width, int height, const SkMatrix& initialTransform)
    : PlatformDevice(makeABitmap(width, height)),
      pdf_device_(new SkPDFDevice(width, height, initialTransform)) {
  pdf_device_->unref();  // SkRefPtr and new both took a reference.
}

VectorPlatformDeviceSkia::~VectorPlatformDeviceSkia() {
}

bool VectorPlatformDeviceSkia::IsVectorial() {
  return true;
}

bool VectorPlatformDeviceSkia::IsNativeFontRenderingAllowed() {
  return false;
}

PlatformDevice::PlatformSurface VectorPlatformDeviceSkia::BeginPlatformPaint() {
  // Even when drawing a vector representation of the page, we have to
  // provide a raster surface for plugins to render into - they don't have
  // a vector interface.  Therefore we create a BitmapPlatformDevice here
  // and return the context from it, then layer on the raster data as an
  // image in EndPlatformPaint.
  DCHECK(raster_surface_ == NULL);
#if defined(OS_WIN)
  raster_surface_ = BitmapPlatformDevice::create(pdf_device_->width(),
                                                 pdf_device_->height(),
                                                 false, /* not opaque */
                                                 NULL);
#elif defined(OS_LINUX)
  raster_surface_ = BitmapPlatformDevice::Create(pdf_device_->width(),
                                                 pdf_device_->height(),
                                                 false /* not opaque */);
#endif
  raster_surface_->unref();  // SkRefPtr and create both took a reference.

  SkCanvas canvas(raster_surface_.get());
  SkPaint black;
  black.setColor(SK_ColorBLACK);
  canvas.drawPaint(black);
  return raster_surface_->BeginPlatformPaint();
}

void VectorPlatformDeviceSkia::EndPlatformPaint() {
  DCHECK(raster_surface_ != NULL);
  SkPaint paint;
  pdf_device_->drawSprite(SkDraw(), raster_surface_->accessBitmap(false),
                          0, 0, paint);
  raster_surface_ = NULL;
}

SkDeviceFactory* VectorPlatformDeviceSkia::getDeviceFactory() {
  return SkNEW(VectorPlatformDeviceSkiaFactory);
}

uint32_t VectorPlatformDeviceSkia::getDeviceCapabilities() {
  return kVector_Capability;
}

int VectorPlatformDeviceSkia::width() const {
  return pdf_device_->width();
}

int VectorPlatformDeviceSkia::height() const {
  return pdf_device_->height();
}

void VectorPlatformDeviceSkia::setMatrixClip(const SkMatrix& matrix,
                                             const SkRegion& region,
                                             const SkClipStack& stack) {
  pdf_device_->setMatrixClip(matrix, region, stack);
}

bool VectorPlatformDeviceSkia::readPixels(const SkIRect& srcRect,
                                          SkBitmap* bitmap) {
  return false;
}

void VectorPlatformDeviceSkia::drawPaint(const SkDraw& draw,
                                         const SkPaint& paint) {
  pdf_device_->drawPaint(draw, paint);
}

void VectorPlatformDeviceSkia::drawPoints(const SkDraw& draw,
                                          SkCanvas::PointMode mode,
                                          size_t count, const SkPoint pts[],
                                          const SkPaint& paint) {
  pdf_device_->drawPoints(draw, mode, count, pts, paint);
}

void VectorPlatformDeviceSkia::drawRect(const SkDraw& draw,
                                        const SkRect& rect,
                                        const SkPaint& paint) {
  pdf_device_->drawRect(draw, rect, paint);
}

void VectorPlatformDeviceSkia::drawPath(const SkDraw& draw,
                                        const SkPath& path,
                                        const SkPaint& paint,
                                        const SkMatrix* prePathMatrix,
                                        bool pathIsMutable) {
  pdf_device_->drawPath(draw, path, paint, prePathMatrix, pathIsMutable);
}

void VectorPlatformDeviceSkia::drawBitmap(const SkDraw& draw,
                                          const SkBitmap& bitmap,
                                          const SkIRect* srcRectOrNull,
                                          const SkMatrix& matrix,
                                          const SkPaint& paint) {
  pdf_device_->drawBitmap(draw, bitmap, srcRectOrNull, matrix, paint);
}

void VectorPlatformDeviceSkia::drawSprite(const SkDraw& draw,
                                          const SkBitmap& bitmap,
                                          int x, int y,
                                          const SkPaint& paint) {
  pdf_device_->drawSprite(draw, bitmap, x, y, paint);
}

void VectorPlatformDeviceSkia::drawText(const SkDraw& draw,
                                        const void* text,
                                        size_t byteLength,
                                        SkScalar x,
                                        SkScalar y,
                                        const SkPaint& paint) {
  pdf_device_->drawText(draw, text, byteLength, x, y, paint);
}

void VectorPlatformDeviceSkia::drawPosText(const SkDraw& draw,
                                           const void* text,
                                           size_t len,
                                           const SkScalar pos[],
                                           SkScalar constY,
                                           int scalarsPerPos,
                                           const SkPaint& paint) {
  pdf_device_->drawPosText(draw, text, len, pos, constY, scalarsPerPos, paint);
}

void VectorPlatformDeviceSkia::drawTextOnPath(const SkDraw& draw,
                                              const void* text,
                                              size_t len,
                                              const SkPath& path,
                                              const SkMatrix* matrix,
                                              const SkPaint& paint) {
  pdf_device_->drawTextOnPath(draw, text, len, path, matrix, paint);
}

void VectorPlatformDeviceSkia::drawVertices(const SkDraw& draw,
                                            SkCanvas::VertexMode vmode,
                                            int vertexCount,
                                            const SkPoint vertices[],
                                            const SkPoint texs[],
                                            const SkColor colors[],
                                            SkXfermode* xmode,
                                            const uint16_t indices[],
                                            int indexCount,
                                            const SkPaint& paint) {
  pdf_device_->drawVertices(draw, vmode, vertexCount, vertices, texs, colors,
                            xmode, indices, indexCount, paint);
}

void VectorPlatformDeviceSkia::drawDevice(const SkDraw& draw,
                                          SkDevice* device,
                                          int x,
                                          int y,
                                          const SkPaint& paint) {
  SkDevice* real_device = device;
  if ((device->getDeviceCapabilities() & kVector_Capability)) {
    // Assume that a vectorial device means a VectorPlatformDeviceSkia, we need
    // to unwrap the embedded SkPDFDevice.
    VectorPlatformDeviceSkia* vector_device =
        static_cast<VectorPlatformDeviceSkia*>(device);
    real_device = vector_device->pdf_device_.get();
  }
  pdf_device_->drawDevice(draw, real_device, x, y, paint);
}

#if defined(OS_WIN)
void VectorPlatformDeviceSkia::drawToHDC(HDC dc,
                                         int x,
                                         int y,
                                         const RECT* src_rect) {
  SkASSERT(false);
}
#endif

}  // namespace skia
<commit_msg>Phoney SkDraw needs more after skia rev 1141.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "skia/ext/vector_platform_device_skia.h"

#include "skia/ext/bitmap_platform_device.h"
#include "third_party/skia/include/core/SkClipStack.h"
#include "third_party/skia/include/core/SkDraw.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "third_party/skia/include/core/SkScalar.h"

namespace skia {

SkDevice* VectorPlatformDeviceSkiaFactory::newDevice(SkCanvas* noUsed,
                                                     SkBitmap::Config config,
                                                     int width, int height,
                                                     bool isOpaque,
                                                     bool isForLayer) {
  SkASSERT(config == SkBitmap::kARGB_8888_Config);
  SkMatrix initialTransform;
  initialTransform.reset();
  if (isForLayer) {
    initialTransform.setTranslate(0, height);
    initialTransform.preScale(1, -1);
  }
  return new VectorPlatformDeviceSkia(width, height, initialTransform);
}

static inline SkBitmap makeABitmap(int width, int height) {
  SkBitmap bitmap;
  bitmap.setConfig(SkBitmap::kNo_Config, width, height);
  return bitmap;
}

VectorPlatformDeviceSkia::VectorPlatformDeviceSkia(
    int width, int height, const SkMatrix& initialTransform)
    : PlatformDevice(makeABitmap(width, height)),
      pdf_device_(new SkPDFDevice(width, height, initialTransform)) {
  pdf_device_->unref();  // SkRefPtr and new both took a reference.
}

VectorPlatformDeviceSkia::~VectorPlatformDeviceSkia() {
}

bool VectorPlatformDeviceSkia::IsVectorial() {
  return true;
}

bool VectorPlatformDeviceSkia::IsNativeFontRenderingAllowed() {
  return false;
}

PlatformDevice::PlatformSurface VectorPlatformDeviceSkia::BeginPlatformPaint() {
  // Even when drawing a vector representation of the page, we have to
  // provide a raster surface for plugins to render into - they don't have
  // a vector interface.  Therefore we create a BitmapPlatformDevice here
  // and return the context from it, then layer on the raster data as an
  // image in EndPlatformPaint.
  DCHECK(raster_surface_ == NULL);
#if defined(OS_WIN)
  raster_surface_ = BitmapPlatformDevice::create(pdf_device_->width(),
                                                 pdf_device_->height(),
                                                 false, /* not opaque */
                                                 NULL);
#elif defined(OS_LINUX)
  raster_surface_ = BitmapPlatformDevice::Create(pdf_device_->width(),
                                                 pdf_device_->height(),
                                                 false /* not opaque */);
#endif
  raster_surface_->unref();  // SkRefPtr and create both took a reference.

  SkCanvas canvas(raster_surface_.get());
  SkPaint black;
  black.setColor(SK_ColorBLACK);
  canvas.drawPaint(black);
  return raster_surface_->BeginPlatformPaint();
}

void VectorPlatformDeviceSkia::EndPlatformPaint() {
  DCHECK(raster_surface_ != NULL);
  SkPaint paint;
  // SkPDFDevice checks the passed SkDraw for an empty clip (only).  Fake
  // it out by setting a non-empty clip.
  SkDraw draw;
  SkRegion clip(SkIRect::MakeWH(pdf_device_->width(), pdf_device_->height()));
  draw.fClip=&clip;
  pdf_device_->drawSprite(draw, raster_surface_->accessBitmap(false), 0, 0,
                          paint);
  raster_surface_ = NULL;
}

SkDeviceFactory* VectorPlatformDeviceSkia::getDeviceFactory() {
  return SkNEW(VectorPlatformDeviceSkiaFactory);
}

uint32_t VectorPlatformDeviceSkia::getDeviceCapabilities() {
  return kVector_Capability;
}

int VectorPlatformDeviceSkia::width() const {
  return pdf_device_->width();
}

int VectorPlatformDeviceSkia::height() const {
  return pdf_device_->height();
}

void VectorPlatformDeviceSkia::setMatrixClip(const SkMatrix& matrix,
                                             const SkRegion& region,
                                             const SkClipStack& stack) {
  pdf_device_->setMatrixClip(matrix, region, stack);
}

bool VectorPlatformDeviceSkia::readPixels(const SkIRect& srcRect,
                                          SkBitmap* bitmap) {
  return false;
}

void VectorPlatformDeviceSkia::drawPaint(const SkDraw& draw,
                                         const SkPaint& paint) {
  pdf_device_->drawPaint(draw, paint);
}

void VectorPlatformDeviceSkia::drawPoints(const SkDraw& draw,
                                          SkCanvas::PointMode mode,
                                          size_t count, const SkPoint pts[],
                                          const SkPaint& paint) {
  pdf_device_->drawPoints(draw, mode, count, pts, paint);
}

void VectorPlatformDeviceSkia::drawRect(const SkDraw& draw,
                                        const SkRect& rect,
                                        const SkPaint& paint) {
  pdf_device_->drawRect(draw, rect, paint);
}

void VectorPlatformDeviceSkia::drawPath(const SkDraw& draw,
                                        const SkPath& path,
                                        const SkPaint& paint,
                                        const SkMatrix* prePathMatrix,
                                        bool pathIsMutable) {
  pdf_device_->drawPath(draw, path, paint, prePathMatrix, pathIsMutable);
}

void VectorPlatformDeviceSkia::drawBitmap(const SkDraw& draw,
                                          const SkBitmap& bitmap,
                                          const SkIRect* srcRectOrNull,
                                          const SkMatrix& matrix,
                                          const SkPaint& paint) {
  pdf_device_->drawBitmap(draw, bitmap, srcRectOrNull, matrix, paint);
}

void VectorPlatformDeviceSkia::drawSprite(const SkDraw& draw,
                                          const SkBitmap& bitmap,
                                          int x, int y,
                                          const SkPaint& paint) {
  pdf_device_->drawSprite(draw, bitmap, x, y, paint);
}

void VectorPlatformDeviceSkia::drawText(const SkDraw& draw,
                                        const void* text,
                                        size_t byteLength,
                                        SkScalar x,
                                        SkScalar y,
                                        const SkPaint& paint) {
  pdf_device_->drawText(draw, text, byteLength, x, y, paint);
}

void VectorPlatformDeviceSkia::drawPosText(const SkDraw& draw,
                                           const void* text,
                                           size_t len,
                                           const SkScalar pos[],
                                           SkScalar constY,
                                           int scalarsPerPos,
                                           const SkPaint& paint) {
  pdf_device_->drawPosText(draw, text, len, pos, constY, scalarsPerPos, paint);
}

void VectorPlatformDeviceSkia::drawTextOnPath(const SkDraw& draw,
                                              const void* text,
                                              size_t len,
                                              const SkPath& path,
                                              const SkMatrix* matrix,
                                              const SkPaint& paint) {
  pdf_device_->drawTextOnPath(draw, text, len, path, matrix, paint);
}

void VectorPlatformDeviceSkia::drawVertices(const SkDraw& draw,
                                            SkCanvas::VertexMode vmode,
                                            int vertexCount,
                                            const SkPoint vertices[],
                                            const SkPoint texs[],
                                            const SkColor colors[],
                                            SkXfermode* xmode,
                                            const uint16_t indices[],
                                            int indexCount,
                                            const SkPaint& paint) {
  pdf_device_->drawVertices(draw, vmode, vertexCount, vertices, texs, colors,
                            xmode, indices, indexCount, paint);
}

void VectorPlatformDeviceSkia::drawDevice(const SkDraw& draw,
                                          SkDevice* device,
                                          int x,
                                          int y,
                                          const SkPaint& paint) {
  SkDevice* real_device = device;
  if ((device->getDeviceCapabilities() & kVector_Capability)) {
    // Assume that a vectorial device means a VectorPlatformDeviceSkia, we need
    // to unwrap the embedded SkPDFDevice.
    VectorPlatformDeviceSkia* vector_device =
        static_cast<VectorPlatformDeviceSkia*>(device);
    real_device = vector_device->pdf_device_.get();
  }
  pdf_device_->drawDevice(draw, real_device, x, y, paint);
}

#if defined(OS_WIN)
void VectorPlatformDeviceSkia::drawToHDC(HDC dc,
                                         int x,
                                         int y,
                                         const RECT* src_rect) {
  SkASSERT(false);
}
#endif

}  // namespace skia
<|endoftext|>