##############################################################################
# Common libraries / utilities
-include_directories (${CMAKE_CURRENT_SOURCE_DIR})
+include_directories (
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/common
+)
add_custom_command (
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/glproc.hpp
endif (WIN32)
add_library (common
- trace_file.cpp
- trace_snappyfile.cpp
- trace_model.cpp
- trace_parser.cpp
- trace_writer.cpp
- trace_local_writer.cpp
- trace_model_writer.cpp
- trace_loader.cpp
- image.cpp
- image_bmp.cpp
- image_pnm.cpp
- image_png.cpp
- ${os}
+ common/trace_file.cpp
+ common/trace_snappyfile.cpp
+ common/trace_model.cpp
+ common/trace_parser.cpp
+ common/trace_writer.cpp
+ common/trace_local_writer.cpp
+ common/trace_model_writer.cpp
+ common/trace_loader.cpp
+ common/image.cpp
+ common/image_bmp.cpp
+ common/image_pnm.cpp
+ common/image_png.cpp
+ common/${os}
)
set_target_properties (common PROPERTIES
glstate_params.cpp
retrace.cpp
${glws}
- image.cpp
${CMAKE_CURRENT_BINARY_DIR}/glproc.hpp
)
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Helpers for coloring output.
+ */
+
+#ifndef _FORMATTER_HPP_
+#define _FORMATTER_HPP_
+
+
+#include <iostream>
+
+
+namespace Formatter {
+
+/*
+ * See also http://bytes.com/topic/c/answers/63822-design-question-little-c-header-colorizing-text-linux-comments-ideas
+ */
+
+class Attribute {
+public:
+ virtual ~Attribute() {}
+
+ virtual void apply(std::ostream &) const {}
+};
+
+
+enum Color {
+ RED,
+ GREEN,
+ BLUE,
+};
+
+
+class Formatter {
+public:
+ virtual ~Formatter() {}
+
+ virtual Attribute *normal(void) const { return new Attribute; }
+ virtual Attribute *bold(void) const { return new Attribute; }
+ virtual Attribute *italic(void) const { return new Attribute; }
+ virtual Attribute *color(Color) const { return new Attribute; }
+};
+
+
+class AnsiAttribute : public Attribute {
+protected:
+ const char *escape;
+public:
+ AnsiAttribute(const char *_escape) : escape(_escape) {}
+ void apply(std::ostream& os) const {
+ os << "\33[" << escape;
+ }
+};
+
+
+/**
+ * Formatter for plain-text files which outputs ANSI escape codes. See
+ * http://en.wikipedia.org/wiki/ANSI_escape_code for more information
+ * concerning ANSI escape codes.
+ */
+class AnsiFormatter : public Formatter {
+protected:
+public:
+ virtual Attribute *normal(void) const { return new AnsiAttribute("0m"); }
+ virtual Attribute *bold(void) const { return new AnsiAttribute("1m"); }
+ virtual Attribute *italic(void) const { return new AnsiAttribute("3m"); }
+ virtual Attribute *color(Color c) const {
+ static const char *color_escapes[] = {
+ "31m", /* red */
+ "32m", /* green */
+ "34m", /* blue */
+ };
+ return new AnsiAttribute(color_escapes[c]);
+ }
+};
+
+
+inline std::ostream& operator<<(std::ostream& os, const Attribute *attr) {
+ attr->apply(os);
+ return os;
+}
+
+
+#ifdef _WIN32
+
+#include <windows.h>
+
+class WindowsAttribute : public Attribute {
+protected:
+ WORD wAttributes;
+public:
+ WindowsAttribute(WORD _wAttributes) : wAttributes(_wAttributes) {}
+ void apply(std::ostream& os) const {
+ DWORD nStdHandleOutput;
+ if (os == std::cout) {
+ nStdHandleOutput = STD_OUTPUT_HANDLE;
+ } else if (os == std::cerr) {
+ nStdHandleOutput = STD_ERROR_HANDLE;
+ } else {
+ return;
+ }
+ HANDLE hConsoleOutput = GetStdHandle(nStdHandleOutput);
+ if (hConsoleOutput == INVALID_HANDLE_VALUE) {
+ return;
+ }
+
+ SetConsoleTextAttribute(hConsoleOutput, wAttributes);
+ }
+};
+
+
+/**
+ * Formatter for the Windows Console.
+ */
+class WindowsFormatter : public Formatter {
+protected:
+public:
+ virtual Attribute *normal(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); }
+ virtual Attribute *bold(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY); }
+ virtual Attribute *italic(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); }
+ virtual Attribute *color(Color c) const {
+ static const WORD color_escapes[] = {
+ FOREGROUND_RED | FOREGROUND_INTENSITY,
+ FOREGROUND_GREEN | FOREGROUND_INTENSITY,
+ FOREGROUND_BLUE | FOREGROUND_INTENSITY,
+ };
+ return new WindowsAttribute(color_escapes[c]);
+ }
+};
+
+#endif
+
+
+inline Formatter *defaultFormatter(bool color = true) {
+ if (color) {
+#ifdef _WIN32
+ return new WindowsFormatter;
+#else
+ return new AnsiFormatter;
+#endif
+ } else {
+ return new Formatter;
+ }
+}
+
+
+} /* namespace Formatter */
+
+
+#endif /* _FORMATTER_HPP_ */
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * Copyright 2008-2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+
+#include <assert.h>
+#include <math.h>
+
+#include "image.hpp"
+
+
+namespace Image {
+
+
+double Image::compare(Image &ref)
+{
+ if (width != ref.width ||
+ height != ref.height ||
+ channels != ref.channels) {
+ return 0.0;
+ }
+
+ const unsigned char *pSrc = start();
+ const unsigned char *pRef = ref.start();
+
+ assert(channels >= 3);
+
+ unsigned long long error = 0;
+ for (unsigned y = 0; y < height; ++y) {
+ for (unsigned x = 0; x < width; ++x) {
+ // FIXME: Ignore alpha channel until we are able to pick a visual
+ // that matches the traces
+ for (unsigned c = 0; c < 3; ++c) {
+ int delta = pSrc[x*channels + c] - pRef[x*channels + c];
+ error += delta*delta;
+ }
+ }
+
+ pSrc += stride();
+ pRef += ref.stride();
+ }
+
+ double numerator = error*2 + 1;
+ double denominator = height*width*3ULL*255ULL*255ULL*2;
+ double quotient = numerator/denominator;
+
+ // Precision in bits
+ double precision = -log(quotient)/log(2.0);
+
+ return precision;
+}
+
+
+} /* namespace Image */
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2008-2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Image I/O.
+ */
+
+#ifndef _IMAGE_HPP_
+#define _IMAGE_HPP_
+
+
+#include <fstream>
+
+
+namespace Image {
+
+
+class Image {
+public:
+ unsigned width;
+ unsigned height;
+ unsigned channels;
+
+ // Flipped vertically or not
+ bool flipped;
+
+ // Pixels in RGBA format
+ unsigned char *pixels;
+
+ inline Image(unsigned w, unsigned h, unsigned c = 4, bool f = false) :
+ width(w),
+ height(h),
+ channels(c),
+ flipped(f),
+ pixels(new unsigned char[h*w*c])
+ {}
+
+ inline ~Image() {
+ delete [] pixels;
+ }
+
+ inline unsigned char *start(void) {
+ return flipped ? pixels + (height - 1)*width*channels : pixels;
+ }
+
+ inline const unsigned char *start(void) const {
+ return flipped ? pixels + (height - 1)*width*channels : pixels;
+ }
+
+ inline unsigned char *end(void) {
+ return flipped ? pixels - width*channels : pixels + height*width*channels;
+ }
+
+ inline const unsigned char *end(void) const {
+ return flipped ? pixels - width*channels : pixels + height*width*channels;
+ }
+
+ inline signed stride(void) const {
+ return flipped ? -width*channels : width*channels;
+ }
+
+ bool writeBMP(const char *filename) const;
+
+ void writePNM(std::ostream &os, const char *comment = NULL) const;
+
+ inline bool writePNM(const char *filename, const char *comment = NULL) const {
+ std::ofstream os(filename, std::ofstream::binary);
+ if (!os) {
+ return false;
+ }
+ writePNM(os, comment);
+ return true;
+ }
+
+ bool writePNG(const char *filename) const;
+
+ double compare(Image &ref);
+};
+
+bool writePixelsToBuffer(unsigned char *pixels,
+ unsigned w, unsigned h, unsigned numChannels,
+ bool flipped,
+ char **buffer,
+ int *size);
+
+Image *
+readPNG(const char *filename);
+
+
+} /* namespace Image */
+
+
+#endif /* _IMAGE_HPP_ */
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * Copyright 2008-2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "image.hpp"
+
+
+namespace Image {
+
+
+#pragma pack(push,2)
+struct FileHeader {
+ uint16_t bfType;
+ uint32_t bfSize;
+ uint16_t bfReserved1;
+ uint16_t bfReserved2;
+ uint32_t bfOffBits;
+};
+#pragma pack(pop)
+
+struct InfoHeader {
+ uint32_t biSize;
+ int32_t biWidth;
+ int32_t biHeight;
+ uint16_t biPlanes;
+ uint16_t biBitCount;
+ uint32_t biCompression;
+ uint32_t biSizeImage;
+ int32_t biXPelsPerMeter;
+ int32_t biYPelsPerMeter;
+ uint32_t biClrUsed;
+ uint32_t biClrImportant;
+};
+
+struct Pixel {
+ uint8_t rgbBlue;
+ uint8_t rgbGreen;
+ uint8_t rgbRed;
+ uint8_t rgbAlpha;
+};
+
+
+bool
+Image::writeBMP(const char *filename) const {
+ assert(channels == 4);
+
+ struct FileHeader bmfh;
+ struct InfoHeader bmih;
+ unsigned x, y;
+
+ bmfh.bfType = 0x4d42;
+ bmfh.bfSize = 14 + 40 + height*width*4;
+ bmfh.bfReserved1 = 0;
+ bmfh.bfReserved2 = 0;
+ bmfh.bfOffBits = 14 + 40;
+
+ bmih.biSize = 40;
+ bmih.biWidth = width;
+ bmih.biHeight = height;
+ bmih.biPlanes = 1;
+ bmih.biBitCount = 32;
+ bmih.biCompression = 0;
+ bmih.biSizeImage = height*width*4;
+ bmih.biXPelsPerMeter = 0;
+ bmih.biYPelsPerMeter = 0;
+ bmih.biClrUsed = 0;
+ bmih.biClrImportant = 0;
+
+ std::ofstream stream(filename, std::ofstream::binary);
+
+ if (!stream) {
+ return false;
+ }
+
+ stream.write((const char *)&bmfh, 14);
+ stream.write((const char *)&bmih, 40);
+
+ unsigned stride = width*4;
+
+ if (flipped) {
+ for (y = 0; y < height; ++y) {
+ const unsigned char *ptr = pixels + y * stride;
+ for (x = 0; x < width; ++x) {
+ struct Pixel pixel;
+ pixel.rgbRed = ptr[x*4 + 0];
+ pixel.rgbGreen = ptr[x*4 + 1];
+ pixel.rgbBlue = ptr[x*4 + 2];
+ pixel.rgbAlpha = ptr[x*4 + 3];
+ stream.write((const char *)&pixel, 4);
+ }
+ }
+ } else {
+ y = height;
+ while (y--) {
+ const unsigned char *ptr = pixels + y * stride;
+ for (x = 0; x < width; ++x) {
+ struct Pixel pixel;
+ pixel.rgbRed = ptr[x*4 + 0];
+ pixel.rgbGreen = ptr[x*4 + 1];
+ pixel.rgbBlue = ptr[x*4 + 2];
+ pixel.rgbAlpha = ptr[x*4 + 3];
+ stream.write((const char *)&pixel, 4);
+ }
+ }
+ }
+
+ stream.close();
+
+ return true;
+}
+
+
+} /* namespace Image */
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * Copyright 2008-2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+
+#include <zlib.h>
+#include <png.h>
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <fstream>
+
+#include "image.hpp"
+
+
+namespace Image {
+
+
+bool
+Image::writePNG(const char *filename) const {
+ FILE *fp;
+ png_structp png_ptr;
+ png_infop info_ptr;
+
+ fp = fopen(filename, "wb");
+ if (!fp)
+ goto no_fp;
+
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ goto no_png;
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ png_destroy_write_struct(&png_ptr, NULL);
+ goto no_png;
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ goto no_png;
+ }
+
+ png_init_io(png_ptr, fp);
+
+ int color_type;
+ switch (channels) {
+ case 4:
+ color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ break;
+ case 3:
+ color_type = PNG_COLOR_TYPE_RGB;
+ break;
+ case 2:
+ color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
+ break;
+ case 1:
+ color_type = PNG_COLOR_TYPE_GRAY;
+ break;
+ default:
+ assert(0);
+ return false;
+ }
+
+ png_set_IHDR(png_ptr, info_ptr, width, height, 8, color_type,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
+
+ png_write_info(png_ptr, info_ptr);
+
+ if (!flipped) {
+ for (unsigned y = 0; y < height; ++y) {
+ png_bytep row = (png_bytep)(pixels + y*width*channels);
+ png_write_rows(png_ptr, &row, 1);
+ }
+ } else {
+ unsigned y = height;
+ while (y--) {
+ png_bytep row = (png_bytep)(pixels + y*width*channels);
+ png_write_rows(png_ptr, &row, 1);
+ }
+ }
+
+ png_write_end(png_ptr, info_ptr);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+ fclose(fp);
+ return true;
+
+no_png:
+ fclose(fp);
+no_fp:
+ return false;
+}
+
+
+Image *
+readPNG(const char *filename)
+{
+ FILE *fp;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ png_infop end_info;
+ Image *image;
+
+ fp = fopen(filename, "rb");
+ if (!fp)
+ goto no_fp;
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ goto no_png;
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
+ goto no_png;
+ }
+
+ end_info = png_create_info_struct(png_ptr);
+ if (!end_info) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ goto no_png;
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ goto no_png;
+ }
+
+ png_init_io(png_ptr, fp);
+
+ png_read_info(png_ptr, info_ptr);
+
+ png_uint_32 width, height;
+ int bit_depth, color_type, interlace_type, compression_type, filter_method;
+
+ png_get_IHDR(png_ptr, info_ptr,
+ &width, &height,
+ &bit_depth, &color_type, &interlace_type,
+ &compression_type, &filter_method);
+
+ image = new Image(width, height);
+ if (!image)
+ goto no_image;
+
+ /* Convert to RGBA8 */
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_palette_to_rgb(png_ptr);
+ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+ png_set_expand_gray_1_2_4_to_8(png_ptr);
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ png_set_tRNS_to_alpha(png_ptr);
+ if (bit_depth == 16)
+ png_set_strip_16(png_ptr);
+
+ for (unsigned y = 0; y < height; ++y) {
+ png_bytep row = (png_bytep)(image->pixels + y*width*4);
+ png_read_row(png_ptr, row, NULL);
+ }
+
+ png_read_end(png_ptr, info_ptr);
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ fclose(fp);
+ return image;
+
+no_image:
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+no_png:
+ fclose(fp);
+no_fp:
+ return NULL;
+}
+
+
+struct png_tmp_buffer
+{
+ char *buffer;
+ size_t size;
+};
+
+static void
+pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ struct png_tmp_buffer *buf = (struct png_tmp_buffer*) png_get_io_ptr(png_ptr);
+ size_t nsize = buf->size + length;
+
+ /* allocate or grow buffer */
+ if (buf->buffer)
+ buf->buffer = (char*)realloc(buf->buffer, nsize);
+ else
+ buf->buffer = (char*)malloc(nsize);
+
+ if (!buf->buffer)
+ png_error(png_ptr, "Buffer allocation error");
+
+ memcpy(buf->buffer + buf->size, data, length);
+ buf->size += length;
+}
+
+bool writePixelsToBuffer(unsigned char *pixels,
+ unsigned width, unsigned height, unsigned numChannels,
+ bool flipped,
+ char **buffer,
+ int *size)
+{
+ struct png_tmp_buffer png_mem;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ int type;
+
+ png_mem.buffer = NULL;
+ png_mem.size = 0;
+
+ switch (numChannels) {
+ case 4:
+ type = PNG_COLOR_TYPE_RGB_ALPHA;
+ break;
+ case 3:
+ type = PNG_COLOR_TYPE_RGB;
+ break;
+ case 2:
+ type = PNG_COLOR_TYPE_GRAY_ALPHA;
+ break;
+ case 1:
+ type = PNG_COLOR_TYPE_GRAY;
+ break;
+ default:
+ goto no_png;
+ }
+
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ goto no_png;
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ png_destroy_write_struct(&png_ptr, NULL);
+ goto no_png;
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ goto no_png;
+ }
+
+ png_set_write_fn(png_ptr, &png_mem, pngWriteCallback, NULL);
+
+ png_set_IHDR(png_ptr, info_ptr, width, height, 8,
+ type, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
+
+ png_write_info(png_ptr, info_ptr);
+
+ if (!flipped) {
+ for (unsigned y = 0; y < height; ++y) {
+ png_bytep row = (png_bytep)(pixels + y*width*numChannels);
+ png_write_rows(png_ptr, &row, 1);
+ }
+ } else {
+ unsigned y = height;
+ while (y--) {
+ png_bytep row = (png_bytep)(pixels + y*width*numChannels);
+ png_write_rows(png_ptr, &row, 1);
+ }
+ }
+
+ png_write_end(png_ptr, info_ptr);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+ *buffer = png_mem.buffer;
+ *size = png_mem.size;
+
+ return true;
+
+no_png:
+ *buffer = NULL;
+ *size = 0;
+
+ if (png_mem.buffer)
+ free(png_mem.buffer);
+ return false;
+}
+
+} /* namespace Image */
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * Copyright 2008-2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+
+#include <assert.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "image.hpp"
+
+
+namespace Image {
+
+/**
+ * http://en.wikipedia.org/wiki/Netpbm_format
+ * http://netpbm.sourceforge.net/doc/ppm.html
+ */
+void
+Image::writePNM(std::ostream &os, const char *comment) const {
+ assert(channels == 1 || channels >= 3);
+
+ os << (channels == 1 ? "P5" : "P6") << "\n";
+ if (comment) {
+ os << "#" << comment << "\n";
+ }
+ os << width << " " << height << "\n";
+ os << "255" << "\n";
+
+ const unsigned char *row;
+
+ if (channels == 1 || channels == 3) {
+ for (row = start(); row != end(); row += stride()) {
+ os.write((const char *)row, width*channels);
+ }
+ } else {
+ unsigned char *tmp = new unsigned char[width*3];
+ if (channels == 4) {
+ for (row = start(); row != end(); row += stride()) {
+ const uint32_t *src = (const uint32_t *)row;
+ uint32_t *dst = (uint32_t *)tmp;
+ unsigned x;
+ for (x = 0; x + 4 <= width; x += 4) {
+ /*
+ * It's much faster to access dwords than bytes.
+ *
+ * FIXME: Big-endian version.
+ */
+
+ uint32_t rgba0 = *src++ & 0xffffff;
+ uint32_t rgba1 = *src++ & 0xffffff;
+ uint32_t rgba2 = *src++ & 0xffffff;
+ uint32_t rgba3 = *src++ & 0xffffff;
+ uint32_t rgb0 = rgba0
+ | (rgba1 << 24);
+ uint32_t rgb1 = (rgba1 >> 8)
+ | (rgba2 << 16);
+ uint32_t rgb2 = (rgba2 >> 16)
+ | (rgba3 << 8);
+ *dst++ = rgb0;
+ *dst++ = rgb1;
+ *dst++ = rgb2;
+ }
+ for (; x < width; ++x) {
+ tmp[x*3 + 0] = row[x*4 + 0];
+ tmp[x*3 + 1] = row[x*4 + 1];
+ tmp[x*3 + 2] = row[x*4 + 2];
+ }
+ os.write((const char *)tmp, width*3);
+ }
+ } else if (channels == 2) {
+ for (row = start(); row != end(); row += stride()) {
+ const unsigned char *src = row;
+ unsigned char *dst = tmp;
+ for (unsigned x = 0; x < width; ++x) {
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = 0;
+ }
+ os.write((const char *)tmp, width*3);
+ }
+ } else {
+ assert(0);
+ }
+ delete [] tmp;
+ }
+}
+
+
+} /* namespace Image */
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Trace writing functions.
+ */
+
+#ifndef _JSON_HPP_
+#define _JSON_HPP_
+
+#include <assert.h>
+#include <stddef.h>
+#include <wchar.h>
+
+#include <iomanip>
+#include <ostream>
+#include <string>
+
+
+class JSONWriter
+{
+private:
+ std::ostream &os;
+
+ int level;
+ bool value;
+ char space;
+
+ void newline(void) {
+ os << "\n";
+ for (int i = 0; i < level; ++i)
+ os << " ";
+ }
+
+ void separator(void) {
+ if (value) {
+ os << ",";
+ switch (space) {
+ case '\0':
+ break;
+ case '\n':
+ newline();
+ break;
+ default:
+ os << space;
+ break;
+ }
+ } else {
+ if (space == '\n') {
+ newline();
+ }
+ }
+ }
+
+ void escapeAsciiString(const char *str) {
+ os << "\"";
+
+ const unsigned char *src = (const unsigned char *)str;
+ unsigned char c;
+ while ((c = *src++)) {
+ if ((c == '\"') ||
+ (c == '\\')) {
+ // escape character
+ os << '\\' << (unsigned char)c;
+ } else if ((c >= 0x20 && c <= 0x7e) ||
+ c == '\t' ||
+ c == '\r' ||
+ c == '\n') {
+ // pass-through character
+ os << (unsigned char)c;
+ } else {
+ assert(0);
+ os << "?";
+ }
+ }
+
+ os << "\"";
+ }
+
+ void escapeUnicodeString(const char *str) {
+ os << "\"";
+
+ const char *locale = setlocale(LC_CTYPE, "");
+ const char *src = str;
+ mbstate_t state;
+
+ memset(&state, 0, sizeof state);
+
+ do {
+ // Convert characters one at a time in order to recover from
+ // conversion errors
+ wchar_t c;
+ size_t written = mbsrtowcs(&c, &src, 1, &state);
+ if (written == 0) {
+ // completed
+ break;
+ } if (written == (size_t)-1) {
+ // conversion error -- skip
+ os << "?";
+ do {
+ ++src;
+ } while (*src & 0x80);
+ } else if ((c == '\"') ||
+ (c == '\\')) {
+ // escape character
+ os << '\\' << (unsigned char)c;
+ } else if ((c >= 0x20 && c <= 0x7e) ||
+ c == '\t' ||
+ c == '\r' ||
+ c == '\n') {
+ // pass-through character
+ os << (unsigned char)c;
+ } else {
+ // unicode
+ os << "\\u" << std::setfill('0') << std::hex << std::setw(4) << (unsigned)c;
+ os << std::dec;
+ }
+ } while (src);
+
+ setlocale(LC_CTYPE, locale);
+
+ os << "\"";
+ }
+
+ void encodeBase64String(const unsigned char *bytes, size_t size) {
+ const char *table64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ unsigned char c0, c1, c2, c3;
+ char buf[4];
+ unsigned written;
+
+ os << "\"";
+
+ written = 0;
+ while (size >= 3) {
+ c0 = bytes[0] >> 2;
+ c1 = ((bytes[0] & 0x03) << 4) | ((bytes[1] & 0xf0) >> 4);
+ c2 = ((bytes[1] & 0x0f) << 2) | ((bytes[2] & 0xc0) >> 6);
+ c3 = bytes[2] & 0x3f;
+
+ buf[0] = table64[c0];
+ buf[1] = table64[c1];
+ buf[2] = table64[c2];
+ buf[3] = table64[c3];
+
+ os.write(buf, 4);
+
+ bytes += 3;
+ size -= 3;
+ ++written;
+
+ if (written >= 76/4 && size) {
+ os << "\n";
+ written = 0;
+ }
+ }
+
+ if (size > 0) {
+ c0 = bytes[0] >> 2;
+ c1 = ((bytes[0] & 0x03) << 4);
+ buf[2] = '=';
+ buf[3] = '=';
+
+ if (size > 1) {
+ c1 |= ((bytes[1] & 0xf0) >> 4);
+ c2 = ((bytes[1] & 0x0f) << 2);
+ if (size > 2) {
+ c2 |= ((bytes[2] & 0xc0) >> 6);
+ c3 = bytes[2] & 0x3f;
+ buf[3] = table64[c3];
+ }
+ buf[2] = table64[c2];
+ }
+ buf[1] = table64[c1];
+ buf[0] = table64[c0];
+
+ os.write(buf, 4);
+ }
+
+ os << "\"";
+ }
+
+public:
+ JSONWriter(std::ostream &_os) :
+ os(_os),
+ level(0),
+ value(false),
+ space(0)
+ {
+ beginObject();
+ }
+
+ ~JSONWriter() {
+ endObject();
+ newline();
+ }
+
+ inline void beginObject() {
+ separator();
+ os << "{";
+ ++level;
+ value = false;
+ }
+
+ inline void endObject() {
+ --level;
+ if (value)
+ newline();
+ os << "}";
+ value = true;
+ space = '\n';
+ }
+
+ inline void beginMember(const char * name) {
+ space = 0;
+ separator();
+ newline();
+ escapeAsciiString(name);
+ os << ": ";
+ value = false;
+ }
+
+ inline void beginMember(const std::string &name) {
+ beginMember(name.c_str());
+ }
+
+ inline void endMember(void) {
+ assert(value);
+ value = true;
+ space = 0;
+ }
+
+ inline void beginArray() {
+ separator();
+ os << "[";
+ ++level;
+ value = false;
+ space = 0;
+ }
+
+ inline void endArray(void) {
+ --level;
+ if (space == '\n') {
+ newline();
+ }
+ os << "]";
+ value = true;
+ space = '\n';
+ }
+
+ inline void writeString(const char *s) {
+ separator();
+ escapeUnicodeString(s);
+ value = true;
+ space = ' ';
+ }
+
+ inline void writeString(const std::string &s) {
+ writeString(s.c_str());
+ }
+
+ inline void writeBase64(const void *bytes, size_t size) {
+ separator();
+ encodeBase64String((const unsigned char *)bytes, size);
+ value = true;
+ space = ' ';
+ }
+
+ inline void writeNull(void) {
+ separator();
+ os << "null";
+ value = true;
+ space = ' ';
+ }
+
+ inline void writeBool(bool b) {
+ separator();
+ os << (b ? "true" : "false");
+ value = true;
+ space = ' ';
+ }
+
+ template<class T>
+ inline void writeNumber(T n) {
+ if (n != n) {
+ // NaN
+ writeNull();
+ } else {
+ separator();
+ os << std::dec << std::setprecision(9) << n;
+ value = true;
+ space = ' ';
+ }
+ }
+
+ inline void writeStringMember(const char *name, const char *s) {
+ beginMember(name);
+ writeString(s);
+ endMember();
+ }
+
+ inline void writeBoolMember(const char *name, bool b) {
+ beginMember(name);
+ writeBool(b);
+ endMember();
+ }
+
+ template<class T>
+ inline void writeNumberMember(const char *name, T n) {
+ beginMember(name);
+ writeNumber(n);
+ endMember();
+ }
+};
+
+#endif /* _JSON_HPP_ */
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Simple OS abstraction layer.
+ */
+
+#ifndef _OS_HPP_
+#define _OS_HPP_
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifdef _WIN32
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#ifndef vsnprintf
+#define vsnprintf _vsnprintf
+#endif
+#define PATH_SEP '\\'
+#else /* !_WIN32 */
+#define PATH_SEP '/'
+#endif /* !_WIN32 */
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+namespace OS {
+
+void AcquireMutex(void);
+
+void ReleaseMutex(void);
+
+bool GetProcessName(char *str, size_t size);
+bool GetCurrentDir(char *str, size_t size);
+
+void DebugMessage(const char *format, ...)
+#ifdef __GNUC__
+ __attribute__ ((format (printf, 1, 2)))
+#endif
+;
+
+#if defined _WIN32 || defined __CYGWIN__
+ /* We always use .def files on windows for now */
+ #if 0
+ #define PUBLIC __declspec(dllexport)
+ #else
+ #define PUBLIC
+ #endif
+ #define PRIVATE
+#else
+ #if __GNUC__ >= 4
+ #define PUBLIC __attribute__ ((visibility("default")))
+ #define PRIVATE __attribute__ ((visibility("hidden")))
+ #else
+ #define PUBLIC
+ #define PRIVATE
+ #endif
+#endif
+
+/**
+ * Get the current time in microseconds from an unknown base.
+ */
+long long GetTime(void);
+
+void Abort(void);
+
+void SetExceptionCallback(void (*callback)(void));
+void ResetExceptionCallback(void);
+
+} /* namespace OS */
+
+#endif /* _OS_HPP_ */
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2010-2011 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <unistd.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#ifdef __APPLE__
+#include <mach-o/dyld.h>
+#endif
+
+#include "os.hpp"
+
+
+namespace OS {
+
+
+static pthread_mutex_t
+mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+void
+AcquireMutex(void)
+{
+ pthread_mutex_lock(&mutex);
+}
+
+
+void
+ReleaseMutex(void)
+{
+ pthread_mutex_unlock(&mutex);
+}
+
+
+bool
+GetProcessName(char *str, size_t size)
+{
+ char szProcessPath[PATH_MAX + 1];
+ char *lpProcessName;
+
+ // http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
+#ifdef __APPLE__
+ uint32_t len = sizeof szProcessPath;
+ if (_NSGetExecutablePath(szProcessPath, &len) != 0) {
+ *str = 0;
+ return false;
+ }
+#else
+ ssize_t len;
+ len = readlink("/proc/self/exe", szProcessPath, sizeof(szProcessPath) - 1);
+ if (len == -1) {
+ // /proc/self/exe is not available on setuid processes, so fallback to
+ // /proc/self/cmdline.
+ int fd = open("/proc/self/cmdline", O_RDONLY);
+ if (fd >= 0) {
+ len = read(fd, szProcessPath, sizeof(szProcessPath) - 1);
+ close(fd);
+ }
+ }
+ if (len <= 0) {
+ snprintf(str, size, "%i", (int)getpid());
+ return true;
+ }
+#endif
+ szProcessPath[len] = 0;
+
+ lpProcessName = strrchr(szProcessPath, '/');
+ lpProcessName = lpProcessName ? lpProcessName + 1 : szProcessPath;
+
+ strncpy(str, lpProcessName, size);
+ if (size)
+ str[size - 1] = 0;
+
+ return true;
+}
+
+bool
+GetCurrentDir(char *str, size_t size)
+{
+ char *ret;
+ ret = getcwd(str, size);
+ str[size - 1] = 0;
+ return ret ? true : false;
+}
+
+void
+DebugMessage(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ fflush(stdout);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+}
+
+long long GetTime(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_usec + tv.tv_sec*1000000LL;
+}
+
+void
+Abort(void)
+{
+ exit(0);
+}
+
+
+static void (*gCallback)(void) = NULL;
+
+#define NUM_SIGNALS 16
+
+struct sigaction old_actions[NUM_SIGNALS];
+
+
+/*
+ * See also:
+ * - http://sourceware.org/git/?p=glibc.git;a=blob;f=debug/segfault.c
+ * - http://ggi.cvs.sourceforge.net/viewvc/ggi/ggi-core/libgg/gg/cleanup.c?view=markup
+ */
+static void signal_handler(int sig, siginfo_t *info, void *context)
+{
+ static int recursion_count = 0;
+
+ fprintf(stderr, "signal_handler: sig = %i\n", sig);
+
+ if (recursion_count) {
+ fprintf(stderr, "recursion with sig %i\n", sig);
+ } else {
+ if (gCallback) {
+ ++recursion_count;
+ gCallback();
+ --recursion_count;
+ }
+ }
+
+ struct sigaction *old_action;
+ if (sig >= NUM_SIGNALS) {
+ /* This should never happen */
+ fprintf(stderr, "Unexpected signal %i\n", sig);
+ raise(SIGKILL);
+ }
+ old_action = &old_actions[sig];
+
+ if (old_action->sa_flags & SA_SIGINFO) {
+ // Handler is in sa_sigaction
+ old_action->sa_sigaction(sig, info, context);
+ } else {
+ if (old_action->sa_handler == SIG_DFL) {
+ fprintf(stderr, "taking default action for signal %i\n", sig);
+
+#if 1
+ struct sigaction dfl_action;
+ dfl_action.sa_handler = SIG_DFL;
+ sigemptyset (&dfl_action.sa_mask);
+ dfl_action.sa_flags = 0;
+ sigaction(sig, &dfl_action, NULL);
+
+ raise(sig);
+#else
+ raise(SIGKILL);
+#endif
+ } else if (old_action->sa_handler == SIG_IGN) {
+ /* ignore */
+ } else {
+ /* dispatch to handler */
+ old_action->sa_handler(sig);
+ }
+ }
+}
+
+void
+SetExceptionCallback(void (*callback)(void))
+{
+ assert(!gCallback);
+ if (!gCallback) {
+ gCallback = callback;
+
+ struct sigaction new_action;
+ new_action.sa_sigaction = signal_handler;
+ sigemptyset(&new_action.sa_mask);
+ new_action.sa_flags = SA_SIGINFO | SA_RESTART;
+
+
+ for (int sig = 1; sig < NUM_SIGNALS; ++sig) {
+ // SIGKILL and SIGSTOP can't be handled
+ if (sig != SIGKILL && sig != SIGSTOP) {
+ if (sigaction(sig, NULL, &old_actions[sig]) >= 0) {
+ sigaction(sig, &new_action, NULL);
+ }
+ }
+ }
+ }
+}
+
+void
+ResetExceptionCallback(void)
+{
+ gCallback = NULL;
+}
+
+} /* namespace OS */
+
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+#include <windows.h>
+#include <assert.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "os.hpp"
+
+
+namespace OS {
+
+
+/*
+ * Trick from http://locklessinc.com/articles/pthreads_on_windows/
+ */
+static CRITICAL_SECTION
+CriticalSection = {
+ (PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 0
+};
+
+
+void
+AcquireMutex(void)
+{
+ EnterCriticalSection(&CriticalSection);
+}
+
+
+void
+ReleaseMutex(void)
+{
+ LeaveCriticalSection(&CriticalSection);
+}
+
+
+bool
+GetProcessName(char *str, size_t size)
+{
+ char szProcessPath[PATH_MAX];
+ char *lpProcessName;
+ char *lpProcessExt;
+
+ GetModuleFileNameA(NULL, szProcessPath, sizeof(szProcessPath)/sizeof(szProcessPath[0]));
+
+ lpProcessName = strrchr(szProcessPath, '\\');
+ lpProcessName = lpProcessName ? lpProcessName + 1 : szProcessPath;
+
+ lpProcessExt = strrchr(lpProcessName, '.');
+ if (lpProcessExt) {
+ *lpProcessExt = '\0';
+ }
+
+ strncpy(str, lpProcessName, size);
+
+ return true;
+}
+
+bool
+GetCurrentDir(char *str, size_t size)
+{
+ DWORD ret;
+ ret = GetCurrentDirectoryA(size, str);
+ str[size - 1] = 0;
+ return ret == 0 ? false : true;
+}
+
+void
+DebugMessage(const char *format, ...)
+{
+ char buf[4096];
+
+ va_list ap;
+ va_start(ap, format);
+ fflush(stdout);
+ vsnprintf(buf, sizeof buf, format, ap);
+ va_end(ap);
+
+ OutputDebugStringA(buf);
+
+ /*
+ * Also write the message to stderr, when a debugger is not present (to
+ * avoid duplicate messages in command line debuggers).
+ */
+#if _WIN32_WINNT > 0x0400
+ if (!IsDebuggerPresent()) {
+ fflush(stdout);
+ fputs(buf, stderr);
+ fflush(stderr);
+ }
+#endif
+}
+
+long long GetTime(void)
+{
+ static LARGE_INTEGER frequency;
+ LARGE_INTEGER counter;
+ if (!frequency.QuadPart)
+ QueryPerformanceFrequency(&frequency);
+ QueryPerformanceCounter(&counter);
+ return counter.QuadPart*1000000LL/frequency.QuadPart;
+}
+
+void
+Abort(void)
+{
+#ifndef NDEBUG
+ DebugBreak();
+#else
+ ExitProcess(0);
+#endif
+}
+
+
+static LPTOP_LEVEL_EXCEPTION_FILTER prevExceptionFilter = NULL;
+static void (*gCallback)(void) = NULL;
+
+static LONG WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
+{
+ if (gCallback) {
+ gCallback();
+ }
+
+ if (prevExceptionFilter) {
+ return prevExceptionFilter(pExceptionInfo);
+ } else {
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+}
+
+void
+SetExceptionCallback(void (*callback)(void))
+{
+ assert(!gCallback);
+
+ if (!gCallback) {
+ gCallback = callback;
+
+ assert(!prevExceptionFilter);
+ prevExceptionFilter = SetUnhandledExceptionFilter(UnhandledExceptionFilter);
+ }
+}
+
+void
+ResetExceptionCallback(void)
+{
+ gCallback = NULL;
+}
+
+
+} /* namespace OS */
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2011 Zack Rusin
+ * 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.
+ *
+ **************************************************************************/
+
+
+#include "trace_file.hpp"
+
+#include "trace_snappyfile.hpp"
+
+#include <assert.h>
+#include <string.h>
+
+#include <zlib.h>
+
+#include "os.hpp"
+
+#include <iostream>
+
+using namespace Trace;
+
+
+File::File(const std::string &filename,
+ File::Mode mode)
+ : m_mode(mode),
+ m_isOpened(false)
+{
+ if (!filename.empty()) {
+ open(filename, m_mode);
+ }
+}
+
+File::~File()
+{
+ close();
+}
+
+
+void File::setCurrentOffset(const File::Offset &offset)
+{
+ assert(0);
+}
+
+bool File::isZLibCompressed(const std::string &filename)
+{
+ std::fstream stream(filename.c_str(),
+ std::fstream::binary | std::fstream::in);
+ if (!stream.is_open())
+ return false;
+
+ unsigned char byte1, byte2;
+ stream >> byte1;
+ stream >> byte2;
+ stream.close();
+
+ return (byte1 == 0x1f && byte2 == 0x8b);
+}
+
+
+bool File::isSnappyCompressed(const std::string &filename)
+{
+ std::fstream stream(filename.c_str(),
+ std::fstream::binary | std::fstream::in);
+ if (!stream.is_open())
+ return false;
+
+ unsigned char byte1, byte2;
+ stream >> byte1;
+ stream >> byte2;
+ stream.close();
+
+ return (byte1 == SNAPPY_BYTE1 && byte2 == SNAPPY_BYTE2);
+}
+
+typedef struct gz_stream {
+ z_stream stream;
+ int z_err; /* error code for last stream operation */
+ int z_eof; /* set if end of input file */
+ FILE *file; /* .gz file */
+} gz_dummy_stream;
+
+ZLibFile::ZLibFile(const std::string &filename,
+ File::Mode mode)
+ : File(filename, mode),
+ m_gzFile(NULL)
+{
+}
+
+ZLibFile::~ZLibFile()
+{
+}
+
+bool ZLibFile::rawOpen(const std::string &filename, File::Mode mode)
+{
+ m_gzFile = gzopen(filename.c_str(),
+ (mode == File::Write) ? "wb" : "rb");
+
+ if (mode == File::Read && m_gzFile) {
+ //XXX: unfortunately zlib doesn't support
+ // SEEK_END or we could've done:
+ //m_endOffset = gzseek(m_gzFile, 0, SEEK_END);
+ //gzrewind(m_gzFile);
+ gz_dummy_stream *stream = (gz_dummy_stream *)m_gzFile;
+ long loc = ftell(stream->file);
+ fseek(stream->file,0,SEEK_END);
+ m_endOffset = ftell(stream->file);
+ fseek(stream->file, loc, SEEK_SET);
+ }
+
+ return m_gzFile != NULL;
+}
+
+bool ZLibFile::rawWrite(const void *buffer, size_t length)
+{
+ return gzwrite(m_gzFile, buffer, length) != -1;
+}
+
+bool ZLibFile::rawRead(void *buffer, size_t length)
+{
+ return gzread(m_gzFile, buffer, length) != -1;
+}
+
+int ZLibFile::rawGetc()
+{
+ return gzgetc(m_gzFile);
+}
+
+void ZLibFile::rawClose()
+{
+ if (m_gzFile) {
+ gzclose(m_gzFile);
+ m_gzFile = NULL;
+ }
+}
+
+void ZLibFile::rawFlush()
+{
+ gzflush(m_gzFile, Z_SYNC_FLUSH);
+}
+
+File::Offset ZLibFile::currentOffset()
+{
+ return File::Offset(gztell(m_gzFile));
+}
+
+bool ZLibFile::supportsOffsets() const
+{
+ return false;
+}
+
+bool ZLibFile::rawSkip(size_t)
+{
+ return false;
+}
+
+int ZLibFile::rawPercentRead()
+{
+ gz_dummy_stream *stream = (gz_dummy_stream *)m_gzFile;
+ return 100 * (ftell(stream->file) / m_endOffset);
+}
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2011 Zack Rusin
+ * 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.
+ *
+ **************************************************************************/
+
+
+#ifndef TRACE_FILE_HPP
+#define TRACE_FILE_HPP
+
+#include <string>
+#include <fstream>
+#include <stdint.h>
+
+namespace Trace {
+
+class File {
+public:
+ enum Mode {
+ Read,
+ Write
+ };
+ struct Offset {
+ Offset(uint64_t _chunk = 0, uint32_t _offsetInChunk = 0)
+ : chunk(_chunk),
+ offsetInChunk(_offsetInChunk)
+ {}
+ uint64_t chunk;
+ uint32_t offsetInChunk;
+ };
+
+public:
+ static bool isZLibCompressed(const std::string &filename);
+ static bool isSnappyCompressed(const std::string &filename);
+public:
+ File(const std::string &filename = std::string(),
+ File::Mode mode = File::Read);
+ virtual ~File();
+
+ bool isOpened() const;
+ File::Mode mode() const;
+
+ bool open(const std::string &filename, File::Mode mode);
+ bool write(const void *buffer, size_t length);
+ bool read(void *buffer, size_t length);
+ void close();
+ void flush(void);
+ int getc();
+ bool skip(size_t length);
+ int percentRead();
+
+ virtual bool supportsOffsets() const = 0;
+ virtual File::Offset currentOffset() = 0;
+ virtual void setCurrentOffset(const File::Offset &offset);
+protected:
+ virtual bool rawOpen(const std::string &filename, File::Mode mode) = 0;
+ virtual bool rawWrite(const void *buffer, size_t length) = 0;
+ virtual bool rawRead(void *buffer, size_t length) = 0;
+ virtual int rawGetc() = 0;
+ virtual void rawClose() = 0;
+ virtual void rawFlush() = 0;
+ virtual bool rawSkip(size_t length) = 0;
+ virtual int rawPercentRead() = 0;
+
+protected:
+ File::Mode m_mode;
+ bool m_isOpened;
+};
+
+inline bool File::isOpened() const
+{
+ return m_isOpened;
+}
+
+inline File::Mode File::mode() const
+{
+ return m_mode;
+}
+
+inline bool File::open(const std::string &filename, File::Mode mode)
+{
+ if (m_isOpened) {
+ close();
+ }
+ m_isOpened = rawOpen(filename, mode);
+ m_mode = mode;
+
+ return m_isOpened;
+}
+
+inline bool File::write(const void *buffer, size_t length)
+{
+ if (!m_isOpened || m_mode != File::Write) {
+ return false;
+ }
+ return rawWrite(buffer, length);
+}
+
+inline bool File::read(void *buffer, size_t length)
+{
+ if (!m_isOpened || m_mode != File::Read) {
+ return false;
+ }
+ return rawRead(buffer, length);
+}
+
+inline int File::percentRead()
+{
+ if (!m_isOpened || m_mode != File::Read) {
+ return 0;
+ }
+ return rawPercentRead();
+}
+
+inline void File::close()
+{
+ if (m_isOpened) {
+ rawClose();
+ m_isOpened = false;
+ }
+}
+
+inline void File::flush(void)
+{
+ if (m_mode == File::Write) {
+ rawFlush();
+ }
+}
+
+inline int File::getc()
+{
+ if (!m_isOpened || m_mode != File::Read) {
+ return -1;
+ }
+ return rawGetc();
+}
+
+inline bool File::skip(size_t length)
+{
+ if (!m_isOpened || m_mode != File::Read) {
+ return false;
+ }
+ return rawSkip(length);
+}
+
+class ZLibFile : public File {
+public:
+ ZLibFile(const std::string &filename = std::string(),
+ File::Mode mode = File::Read);
+ virtual ~ZLibFile();
+
+
+ virtual bool supportsOffsets() const;
+ virtual File::Offset currentOffset();
+protected:
+ virtual bool rawOpen(const std::string &filename, File::Mode mode);
+ virtual bool rawWrite(const void *buffer, size_t length);
+ virtual bool rawRead(void *buffer, size_t length);
+ virtual int rawGetc();
+ virtual void rawClose();
+ virtual void rawFlush();
+ virtual bool rawSkip(size_t length);
+ virtual int rawPercentRead();
+private:
+ void *m_gzFile;
+ double m_endOffset;
+};
+
+inline bool
+operator<(const File::Offset &one, const File::Offset &two)
+{
+ return one.chunk < two.chunk ||
+ (one.chunk == two.chunk && one.offsetInChunk < two.offsetInChunk);
+}
+
+inline bool
+operator==(const File::Offset &one, const File::Offset &two)
+{
+ return one.chunk == two.chunk &&
+ one.offsetInChunk == two.offsetInChunk;
+}
+
+inline bool
+operator>=(const File::Offset &one, const File::Offset &two)
+{
+ return one.chunk > two.chunk ||
+ (one.chunk == two.chunk && one.offsetInChunk >= two.offsetInChunk);
+}
+
+inline bool
+operator>(const File::Offset &one, const File::Offset &two)
+{
+ return two < one;
+}
+
+inline bool
+operator<=(const File::Offset &one, const File::Offset &two)
+{
+ return two >= one;
+}
+
+
+}
+
+#endif
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Trace binary format.
+ *
+ * Grammar:
+ *
+ * trace = event* EOF
+ *
+ * event = EVENT_ENTER call_sig call_detail+
+ * | EVENT_LEAVE call_no call_detail+
+ *
+ * call_sig = sig_id ( name arg_names )?
+ *
+ * call_detail = ARG index value
+ * | RET value
+ * | END
+ *
+ * value = NULL
+ * | FALSE
+ * | TRUE
+ * | SINT int
+ * | UINT int
+ * | FLOAT float
+ * | DOUBLE double
+ * | STRING string
+ * | BLOB string
+ * | ENUM enum_sig
+ * | BITMASK bitmask_sig value
+ * | ARRAY length value+
+ * | STRUCT struct_sig value+
+ * | OPAQUE int
+ *
+ * call_sig = id name arg_name*
+ * | id
+ *
+ * enum_sig = id name value
+ * | id
+ *
+ * bitmask_sig = id count (name value)+
+ * | id
+ *
+ * string = length (BYTE)*
+ *
+ */
+
+#ifndef _TRACE_FORMAT_HPP_
+#define _TRACE_FORMAT_HPP_
+
+namespace Trace {
+
+#define TRACE_VERSION 1
+
+enum Event {
+ EVENT_ENTER = 0,
+ EVENT_LEAVE,
+};
+
+enum CallDetail {
+ CALL_END = 0,
+ CALL_ARG,
+ CALL_RET,
+ CALL_THREAD,
+};
+
+enum Type {
+ TYPE_NULL = 0,
+ TYPE_FALSE,
+ TYPE_TRUE,
+ TYPE_SINT,
+ TYPE_UINT,
+ TYPE_FLOAT,
+ TYPE_DOUBLE,
+ TYPE_STRING, // Null terminated, human readible string
+ TYPE_BLOB, // Block of bytes
+ TYPE_ENUM,
+ TYPE_BITMASK,
+ TYPE_ARRAY,
+ TYPE_STRUCT,
+ TYPE_OPAQUE,
+};
+
+
+} /* namespace Trace */
+
+#endif /* _TRACE_FORMAT_HPP_ */
--- /dev/null
+#include "trace_loader.hpp"
+
+
+using namespace Trace;
+
+Loader::Loader()
+ : m_frameMarker(FrameMarker_SwapBuffers)
+{
+}
+
+Loader::~Loader()
+{
+ close();
+}
+
+Loader::FrameMarker Loader::frameMarker() const
+{
+ return m_frameMarker;
+}
+
+void Loader::setFrameMarker(Loader::FrameMarker marker)
+{
+ m_frameMarker = marker;
+}
+
+int Loader::numberOfFrames() const
+{
+ return m_frameBookmarks.size();
+}
+
+int Loader::numberOfCallsInFrame(int frameIdx) const
+{
+ if (frameIdx > m_frameBookmarks.size()) {
+ return 0;
+ }
+ FrameBookmarks::const_iterator itr =
+ m_frameBookmarks.find(frameIdx);
+ return itr->second.numberOfCalls;
+}
+
+bool Loader::open(const char *filename)
+{
+ if (!m_parser.open(filename)) {
+ std::cerr << "error: failed to open " << filename << "\n";
+ return false;
+ }
+ if (!m_parser.supportsOffsets()) {
+ std::cerr << "error: " <<filename<< " doesn't support seeking "
+ << "\n";
+ return false;
+ }
+
+ Trace::Call *call;
+ ParseBookmark startBookmark;
+ int numOfFrames = 0;
+ int numOfCalls = 0;
+ int lastPercentReport = 0;
+
+ m_parser.getBookmark(startBookmark);
+
+ while ((call = m_parser.scan_call())) {
+ ++numOfCalls;
+
+ if (isCallAFrameMarker(call)) {
+ FrameBookmark frameBookmark(startBookmark);
+ frameBookmark.numberOfCalls = numOfCalls;
+
+ m_frameBookmarks[numOfFrames] = frameBookmark;
+ ++numOfFrames;
+
+ if (m_parser.percentRead() - lastPercentReport >= 5) {
+ std::cerr << "\tPercent scanned = "
+ << m_parser.percentRead()
+ << "..."<<std::endl;
+ lastPercentReport = m_parser.percentRead();
+ }
+
+ m_parser.getBookmark(startBookmark);
+ numOfCalls = 0;
+ }
+ //call->dump(std::cout, color);
+ delete call;
+ }
+ return true;
+}
+
+void Loader::close()
+{
+ m_parser.close();
+}
+
+bool Loader::isCallAFrameMarker(const Trace::Call *call) const
+{
+ std::string name = call->name();
+
+ switch (m_frameMarker) {
+ case FrameMarker_SwapBuffers:
+ return name.find("SwapBuffers") != std::string::npos ||
+ name == "CGLFlushDrawable" ||
+ name == "glFrameTerminatorGREMEDY";
+ break;
+ case FrameMarker_Flush:
+ return name == "glFlush";
+ break;
+ case FrameMarker_Finish:
+ return name == "glFinish";
+ break;
+ case FrameMarker_Clear:
+ return name == "glClear";
+ break;
+ }
+ return false;
+}
+
+std::vector<Trace::Call *> Loader::frame(int idx)
+{
+ int numOfCalls = numberOfCallsInFrame(idx);
+ if (numOfCalls) {
+ const FrameBookmark &frameBookmark = m_frameBookmarks[idx];
+ std::vector<Trace::Call*> calls(numOfCalls);
+ m_parser.setBookmark(frameBookmark.start);
+
+ Trace::Call *call;
+ int parsedCalls = 0;
+ while ((call = m_parser.parse_call())) {
+
+ calls[parsedCalls] = call;
+ ++parsedCalls;
+
+ if (isCallAFrameMarker(call)) {
+ break;
+ }
+
+ }
+ assert(parsedCalls == numOfCalls);
+ return calls;
+ }
+ return std::vector<Trace::Call*>();
+}
--- /dev/null
+#ifndef TRACE_LOADER_HPP
+#define TRACE_LOADER_HPP
+
+#include "trace_file.hpp"
+#include "trace_parser.hpp"
+
+#include <string>
+#include <map>
+#include <queue>
+#include <vector>
+
+namespace Trace {
+
+class Frame;
+
+class Loader
+{
+public:
+ enum FrameMarker {
+ FrameMarker_SwapBuffers,
+ FrameMarker_Flush,
+ FrameMarker_Finish,
+ FrameMarker_Clear
+ };
+public:
+ Loader();
+ ~Loader();
+
+ Loader::FrameMarker frameMarker() const;
+ void setFrameMarker(Loader::FrameMarker marker);
+
+ int numberOfFrames() const;
+ int numberOfCallsInFrame(int frameIdx) const;
+
+ bool open(const char *filename);
+ void close();
+
+ std::vector<Trace::Call*> frame(int idx);
+
+private:
+ struct FrameBookmark {
+ FrameBookmark()
+ : numberOfCalls(0)
+ {}
+ FrameBookmark(const ParseBookmark &s)
+ : start(s),
+ numberOfCalls(0)
+ {}
+
+ ParseBookmark start;
+ int numberOfCalls;
+ };
+ bool isCallAFrameMarker(const Trace::Call *call) const;
+
+private:
+ Trace::Parser m_parser;
+ FrameMarker m_frameMarker;
+
+ typedef std::map<int, FrameBookmark> FrameBookmarks;
+ FrameBookmarks m_frameBookmarks;
+};
+
+}
+
+#endif // TRACE_LOADER_HPP
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2007-2011 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "os.hpp"
+#include "trace_file.hpp"
+#include "trace_writer.hpp"
+#include "trace_format.hpp"
+
+
+namespace Trace {
+
+
+static void exceptionCallback(void)
+{
+ OS::DebugMessage("apitrace: flushing trace due to an exception\n");
+ localWriter.flush();
+}
+
+
+LocalWriter::LocalWriter() :
+ acquired(0)
+{}
+
+LocalWriter::~LocalWriter()
+{
+ OS::ResetExceptionCallback();
+}
+
+void
+LocalWriter::open(void) {
+
+ static unsigned dwCounter = 0;
+
+ const char *szExtension = "trace";
+ char szFileName[PATH_MAX];
+ const char *lpFileName;
+
+ lpFileName = getenv("TRACE_FILE");
+ if (lpFileName) {
+ strncpy(szFileName, lpFileName, PATH_MAX);
+ }
+ else {
+ char szProcessName[PATH_MAX];
+ char szCurrentDir[PATH_MAX];
+ OS::GetProcessName(szProcessName, PATH_MAX);
+ OS::GetCurrentDir(szCurrentDir, PATH_MAX);
+
+ for (;;) {
+ FILE *file;
+
+ if (dwCounter)
+ snprintf(szFileName, PATH_MAX, "%s%c%s.%u.%s", szCurrentDir, PATH_SEP, szProcessName, dwCounter, szExtension);
+ else
+ snprintf(szFileName, PATH_MAX, "%s%c%s.%s", szCurrentDir, PATH_SEP, szProcessName, szExtension);
+
+ file = fopen(szFileName, "rb");
+ if (file == NULL)
+ break;
+
+ fclose(file);
+
+ ++dwCounter;
+ }
+ }
+
+ OS::DebugMessage("apitrace: tracing to %s\n", szFileName);
+
+ Writer::open(szFileName);
+
+ OS::SetExceptionCallback(exceptionCallback);
+
+#if 0
+ // For debugging the exception handler
+ *((int *)0) = 0;
+#endif
+}
+
+unsigned LocalWriter::beginEnter(const FunctionSig *sig) {
+ OS::AcquireMutex();
+ ++acquired;
+
+ if (!m_file->isOpened()) {
+ open();
+ }
+
+ return Writer::beginEnter(sig);
+}
+
+void LocalWriter::endEnter(void) {
+ Writer::endEnter();
+ --acquired;
+ OS::ReleaseMutex();
+}
+
+void LocalWriter::beginLeave(unsigned call) {
+ OS::AcquireMutex();
+ ++acquired;
+ Writer::beginLeave(call);
+}
+
+void LocalWriter::endLeave(void) {
+ Writer::endLeave();
+ --acquired;
+ OS::ReleaseMutex();
+}
+
+void LocalWriter::flush(void) {
+ /*
+ * Do nothing if the mutex is already acquired (e.g., if a segfault happen
+ * while writing the file) to prevent dead-lock.
+ */
+
+ if (!acquired) {
+ OS::AcquireMutex();
+ if (m_file->isOpened()) {
+ m_file->flush();
+ }
+ OS::ReleaseMutex();
+ }
+}
+
+
+LocalWriter localWriter;
+
+
+} /* namespace Trace */
+
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+
+#include "formatter.hpp"
+#include "trace_model.hpp"
+
+
+namespace Trace {
+
+
+Call::~Call() {
+ for (unsigned i = 0; i < args.size(); ++i) {
+ delete args[i];
+ }
+
+ if (ret) {
+ delete ret;
+ }
+}
+
+
+String::~String() {
+ delete [] value;
+}
+
+
+Struct::~Struct() {
+ for (std::vector<Value *>::iterator it = members.begin(); it != members.end(); ++it) {
+ delete *it;
+ }
+}
+
+
+Array::~Array() {
+ for (std::vector<Value *>::iterator it = values.begin(); it != values.end(); ++it) {
+ delete *it;
+ }
+}
+
+Blob::~Blob() {
+ // Blobs are often bound and referred during many calls, so we can't delete
+ // them here in that case.
+ //
+ // Once bound there is no way to know when they were unbound, which
+ // effectively means we have to leak them. A better solution would be to
+ // keep a list of bound pointers, and defer the destruction to when the
+ // trace in question has been fully processed.
+ if (!bound) {
+ delete [] buf;
+ }
+}
+
+
+// bool cast
+bool Null ::toBool(void) const { return false; }
+bool Bool ::toBool(void) const { return value; }
+bool SInt ::toBool(void) const { return value != 0; }
+bool UInt ::toBool(void) const { return value != 0; }
+bool Float ::toBool(void) const { return value != 0; }
+bool String ::toBool(void) const { return true; }
+bool Enum ::toBool(void) const { return sig->value != 0; }
+bool Struct ::toBool(void) const { return true; }
+bool Array ::toBool(void) const { return true; }
+bool Blob ::toBool(void) const { return true; }
+bool Pointer::toBool(void) const { return value != 0; }
+
+
+// signed integer cast
+signed long long Value ::toSInt(void) const { assert(0); return 0; }
+signed long long Null ::toSInt(void) const { return 0; }
+signed long long Bool ::toSInt(void) const { return static_cast<signed long long>(value); }
+signed long long SInt ::toSInt(void) const { return value; }
+signed long long UInt ::toSInt(void) const { assert(static_cast<signed long long>(value) >= 0); return static_cast<signed long long>(value); }
+signed long long Float ::toSInt(void) const { return static_cast<signed long long>(value); }
+signed long long Enum ::toSInt(void) const { return sig->value; }
+
+
+// unsigned integer cast
+unsigned long long Value ::toUInt(void) const { assert(0); return 0; }
+unsigned long long Null ::toUInt(void) const { return 0; }
+unsigned long long Bool ::toUInt(void) const { return static_cast<unsigned long long>(value); }
+unsigned long long SInt ::toUInt(void) const { assert(value >= 0); return static_cast<signed long long>(value); }
+unsigned long long UInt ::toUInt(void) const { return value; }
+unsigned long long Float ::toUInt(void) const { return static_cast<unsigned long long>(value); }
+unsigned long long Enum ::toUInt(void) const { assert(sig->value >= 0); return sig->value; }
+
+
+// floating point cast
+float Value ::toFloat(void) const { assert(0); return 0; }
+float Null ::toFloat(void) const { return 0; }
+float Bool ::toFloat(void) const { return static_cast<float>(value); }
+float SInt ::toFloat(void) const { return static_cast<float>(value); }
+float UInt ::toFloat(void) const { return static_cast<float>(value); }
+float Float ::toFloat(void) const { return value; }
+float Enum ::toFloat(void) const { return static_cast<float>(sig->value); }
+
+
+// floating point cast
+double Value ::toDouble(void) const { assert(0); return 0; }
+double Null ::toDouble(void) const { return 0; }
+double Bool ::toDouble(void) const { return static_cast<double>(value); }
+double SInt ::toDouble(void) const { return static_cast<double>(value); }
+double UInt ::toDouble(void) const { return static_cast<double>(value); }
+double Float ::toDouble(void) const { return value; }
+double Enum ::toDouble(void) const { return static_cast<double>(sig->value); }
+
+
+// pointer cast
+void * Value ::toPointer(void) const { assert(0); return NULL; }
+void * Null ::toPointer(void) const { return NULL; }
+void * Blob ::toPointer(void) const { return buf; }
+void * Pointer::toPointer(void) const { return (void *)value; }
+
+void * Value ::toPointer(bool bind) { assert(0); return NULL; }
+void * Null ::toPointer(bool bind) { return NULL; }
+void * Blob ::toPointer(bool bind) { if (bind) bound = true; return buf; }
+void * Pointer::toPointer(bool bind) { return (void *)value; }
+
+
+// pointer cast
+unsigned long long Value ::toUIntPtr(void) const { assert(0); return 0; }
+unsigned long long Null ::toUIntPtr(void) const { return 0; }
+unsigned long long Pointer::toUIntPtr(void) const { return value; }
+
+
+// string cast
+const char * Value ::toString(void) const { assert(0); return NULL; }
+const char * Null ::toString(void) const { return NULL; }
+const char * String::toString(void) const { return value; }
+
+
+// virtual Value::visit()
+void Null ::visit(Visitor &visitor) { visitor.visit(this); }
+void Bool ::visit(Visitor &visitor) { visitor.visit(this); }
+void SInt ::visit(Visitor &visitor) { visitor.visit(this); }
+void UInt ::visit(Visitor &visitor) { visitor.visit(this); }
+void Float ::visit(Visitor &visitor) { visitor.visit(this); }
+void String ::visit(Visitor &visitor) { visitor.visit(this); }
+void Enum ::visit(Visitor &visitor) { visitor.visit(this); }
+void Bitmask::visit(Visitor &visitor) { visitor.visit(this); }
+void Struct ::visit(Visitor &visitor) { visitor.visit(this); }
+void Array ::visit(Visitor &visitor) { visitor.visit(this); }
+void Blob ::visit(Visitor &visitor) { visitor.visit(this); }
+void Pointer::visit(Visitor &visitor) { visitor.visit(this); }
+
+
+void Visitor::visit(Null *) { assert(0); }
+void Visitor::visit(Bool *) { assert(0); }
+void Visitor::visit(SInt *) { assert(0); }
+void Visitor::visit(UInt *) { assert(0); }
+void Visitor::visit(Float *) { assert(0); }
+void Visitor::visit(String *) { assert(0); }
+void Visitor::visit(Enum *node) { assert(0); }
+void Visitor::visit(Bitmask *node) { visit(static_cast<UInt *>(node)); }
+void Visitor::visit(Struct *) { assert(0); }
+void Visitor::visit(Array *) { assert(0); }
+void Visitor::visit(Blob *) { assert(0); }
+void Visitor::visit(Pointer *) { assert(0); }
+
+
+class Dumper : public Visitor
+{
+protected:
+ std::ostream &os;
+ Formatter::Formatter *formatter;
+ Formatter::Attribute *normal;
+ Formatter::Attribute *bold;
+ Formatter::Attribute *italic;
+ Formatter::Attribute *red;
+ Formatter::Attribute *pointer;
+ Formatter::Attribute *literal;
+
+public:
+ Dumper(std::ostream &_os, bool color) : os(_os) {
+ formatter = Formatter::defaultFormatter(color);
+ normal = formatter->normal();
+ bold = formatter->bold();
+ italic = formatter->italic();
+ red = formatter->color(Formatter::RED);
+ pointer = formatter->color(Formatter::GREEN);
+ literal = formatter->color(Formatter::BLUE);
+ }
+
+ ~Dumper() {
+ delete normal;
+ delete bold;
+ delete italic;
+ delete red;
+ delete pointer;
+ delete literal;
+ delete formatter;
+ }
+
+ void visit(Null *) {
+ os << "NULL";
+ }
+
+ void visit(Bool *node) {
+ os << literal << (node->value ? "true" : "false") << normal;
+ }
+
+ void visit(SInt *node) {
+ os << literal << node->value << normal;
+ }
+
+ void visit(UInt *node) {
+ os << literal << node->value << normal;
+ }
+
+ void visit(Float *node) {
+ os << literal << node->value << normal;
+ }
+
+ void visit(String *node) {
+ os << literal << "\"";
+ for (const char *it = node->value; *it; ++it) {
+ unsigned char c = (unsigned char) *it;
+ if (c == '\"')
+ os << "\\\"";
+ else if (c == '\\')
+ os << "\\\\";
+ else if (c >= 0x20 && c <= 0x7e)
+ os << c;
+ else if (c == '\t') {
+ os << "\t";
+ } else if (c == '\r') {
+ // Ignore carriage-return
+ } else if (c == '\n') {
+ // Reset formatting so that it looks correct with 'less -R'
+ os << normal << '\n' << literal;
+ } else {
+ unsigned octal0 = c & 0x7;
+ unsigned octal1 = (c >> 3) & 0x7;
+ unsigned octal2 = (c >> 3) & 0x7;
+ os << "\\";
+ if (octal2)
+ os << octal2;
+ if (octal1)
+ os << octal1;
+ os << octal0;
+ }
+ }
+ os << "\"" << normal;
+ }
+
+ void visit(Enum *node) {
+ os << literal << node->sig->name << normal;
+ }
+
+ void visit(Bitmask *bitmask) {
+ unsigned long long value = bitmask->value;
+ const BitmaskSig *sig = bitmask->sig;
+ bool first = true;
+ for (const BitmaskFlag *it = sig->flags; value != 0 && it != sig->flags + sig->num_flags; ++it) {
+ if ((it->value && (value & it->value) == it->value) ||
+ (!it->value && value == 0)) {
+ if (!first) {
+ os << " | ";
+ }
+ os << literal << it->name << normal;
+ value &= ~it->value;
+ first = false;
+ }
+ }
+ if (value || first) {
+ if (!first) {
+ os << " | ";
+ }
+ os << literal << "0x" << std::hex << value << std::dec << normal;
+ }
+ }
+
+ void visit(Struct *s) {
+ const char *sep = "";
+ os << "{";
+ for (unsigned i = 0; i < s->members.size(); ++i) {
+ os << sep << italic << s->sig->member_names[i] << normal << " = ";
+ _visit(s->members[i]);
+ sep = ", ";
+ }
+ os << "}";
+ }
+
+ void visit(Array *array) {
+ if (array->values.size() == 1) {
+ os << "&";
+ _visit(array->values[0]);
+ }
+ else {
+ const char *sep = "";
+ os << "{";
+ for (std::vector<Value *>::iterator it = array->values.begin(); it != array->values.end(); ++it) {
+ os << sep;
+ _visit(*it);
+ sep = ", ";
+ }
+ os << "}";
+ }
+ }
+
+ void visit(Blob *blob) {
+ os << pointer << "blob(" << blob->size << ")" << normal;
+ }
+
+ void visit(Pointer *p) {
+ os << pointer << "0x" << std::hex << p->value << std::dec << normal;
+ }
+
+ void visit(Call *call) {
+ const char *sep = "";
+ os << bold << call->sig->name << normal << "(";
+ for (unsigned i = 0; i < call->args.size(); ++i) {
+ os << sep << italic << call->sig->arg_names[i] << normal << " = ";
+ if (call->args[i]) {
+ _visit(call->args[i]);
+ } else {
+ os << "?";
+ }
+ sep = ", ";
+ }
+ os << ")";
+ if (call->ret) {
+ os << " = ";
+ _visit(call->ret);
+ }
+ os << "\n";
+ }
+};
+
+
+void Value::dump(std::ostream &os, bool color) {
+ Dumper d(os, color);
+ visit(d);
+}
+
+
+static Null null;
+
+const Value & Value::operator[](size_t index) const {
+ const Array *array = dynamic_cast<const Array *>(this);
+ if (array) {
+ if (index < array->values.size()) {
+ return *array->values[index];
+ }
+ }
+ return null;
+}
+
+void Call::dump(std::ostream &os, bool color) {
+ Dumper d(os, color);
+ os << no << " ";
+ d.visit(this);
+}
+
+
+} /* namespace Trace */
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Object hierarchy for describing the traces in memory.
+ */
+
+#ifndef _TRACE_MODEL_HPP_
+#define _TRACE_MODEL_HPP_
+
+
+#include <assert.h>
+
+#include <map>
+#include <vector>
+#include <iostream>
+
+
+namespace Trace {
+
+
+typedef unsigned Id;
+
+
+struct FunctionSig {
+ Id id;
+ const char *name;
+ unsigned num_args;
+ const char **arg_names;
+};
+
+
+struct StructSig {
+ Id id;
+ const char *name;
+ unsigned num_members;
+ const char **member_names;
+};
+
+
+struct EnumSig {
+ Id id;
+ const char *name;
+ signed long long value;
+};
+
+
+struct BitmaskFlag {
+ const char *name;
+ unsigned long long value;
+};
+
+
+struct BitmaskSig {
+ Id id;
+ unsigned num_flags;
+ const BitmaskFlag *flags;
+};
+
+
+class Visitor;
+
+
+class Value
+{
+public:
+ virtual ~Value() {}
+ virtual void visit(Visitor &visitor) = 0;
+
+ virtual bool toBool(void) const = 0;
+ virtual signed long long toSInt(void) const;
+ virtual unsigned long long toUInt(void) const;
+ virtual float toFloat(void) const;
+ virtual double toDouble(void) const;
+
+ virtual void *toPointer(void) const;
+ virtual void *toPointer(bool bind);
+ virtual unsigned long long toUIntPtr(void) const;
+ virtual const char *toString(void) const;
+
+ const Value & operator[](size_t index) const;
+
+ void dump(std::ostream &os, bool color=true);
+};
+
+
+class Null : public Value
+{
+public:
+ bool toBool(void) const;
+ signed long long toSInt(void) const;
+ unsigned long long toUInt(void) const;
+ virtual float toFloat(void) const;
+ virtual double toDouble(void) const;
+ void *toPointer(void) const;
+ void *toPointer(bool bind);
+ unsigned long long toUIntPtr(void) const;
+ const char *toString(void) const;
+ void visit(Visitor &visitor);
+};
+
+
+class Bool : public Value
+{
+public:
+ Bool(bool _value) : value(_value) {}
+
+ bool toBool(void) const;
+ signed long long toSInt(void) const;
+ unsigned long long toUInt(void) const;
+ virtual float toFloat(void) const;
+ virtual double toDouble(void) const;
+ void visit(Visitor &visitor);
+
+ bool value;
+};
+
+
+class SInt : public Value
+{
+public:
+ SInt(signed long long _value) : value(_value) {}
+
+ bool toBool(void) const;
+ signed long long toSInt(void) const;
+ unsigned long long toUInt(void) const;
+ virtual float toFloat(void) const;
+ virtual double toDouble(void) const;
+ void visit(Visitor &visitor);
+
+ signed long long value;
+};
+
+
+class UInt : public Value
+{
+public:
+ UInt(unsigned long long _value) : value(_value) {}
+
+ bool toBool(void) const;
+ signed long long toSInt(void) const;
+ unsigned long long toUInt(void) const;
+ virtual float toFloat(void) const;
+ virtual double toDouble(void) const;
+ void visit(Visitor &visitor);
+
+ unsigned long long value;
+};
+
+
+class Float : public Value
+{
+public:
+ Float(double _value) : value(_value) {}
+
+ bool toBool(void) const;
+ signed long long toSInt(void) const;
+ unsigned long long toUInt(void) const;
+ virtual float toFloat(void) const;
+ virtual double toDouble(void) const;
+ void visit(Visitor &visitor);
+
+ double value;
+};
+
+
+class String : public Value
+{
+public:
+ String(const char * _value) : value(_value) {}
+ ~String();
+
+ bool toBool(void) const;
+ const char *toString(void) const;
+ void visit(Visitor &visitor);
+
+ const char * value;
+};
+
+
+class Enum : public Value
+{
+public:
+ Enum(const EnumSig *_sig) : sig(_sig) {}
+
+ bool toBool(void) const;
+ signed long long toSInt(void) const;
+ unsigned long long toUInt(void) const;
+ virtual float toFloat(void) const;
+ virtual double toDouble(void) const;
+ void visit(Visitor &visitor);
+
+ const EnumSig *sig;
+};
+
+
+class Bitmask : public UInt
+{
+public:
+ Bitmask(const BitmaskSig *_sig, unsigned long long _value) : UInt(_value), sig(_sig) {}
+
+ void visit(Visitor &visitor);
+
+ const BitmaskSig *sig;
+};
+
+
+class Struct : public Value
+{
+public:
+ Struct(StructSig *_sig) : sig(_sig), members(_sig->num_members) { }
+ ~Struct();
+
+ bool toBool(void) const;
+ void visit(Visitor &visitor);
+
+ const StructSig *sig;
+ std::vector<Value *> members;
+};
+
+
+class Array : public Value
+{
+public:
+ Array(size_t len) : values(len) {}
+ ~Array();
+
+ bool toBool(void) const;
+ void visit(Visitor &visitor);
+
+ std::vector<Value *> values;
+};
+
+
+class Blob : public Value
+{
+public:
+ Blob(size_t _size) {
+ size = _size;
+ buf = new char[_size];
+ bound = false;
+ }
+
+ ~Blob();
+
+ bool toBool(void) const;
+ void *toPointer(void) const;
+ void *toPointer(bool bind);
+ void visit(Visitor &visitor);
+
+ size_t size;
+ char *buf;
+ bool bound;
+};
+
+
+class Pointer : public UInt
+{
+public:
+ Pointer(unsigned long long value) : UInt(value) {}
+
+ bool toBool(void) const;
+ void *toPointer(void) const;
+ void *toPointer(bool bind);
+ unsigned long long toUIntPtr(void) const;
+ void visit(Visitor &visitor);
+};
+
+
+class Visitor
+{
+public:
+ virtual void visit(Null *);
+ virtual void visit(Bool *);
+ virtual void visit(SInt *);
+ virtual void visit(UInt *);
+ virtual void visit(Float *);
+ virtual void visit(String *);
+ virtual void visit(Enum *);
+ virtual void visit(Bitmask *);
+ virtual void visit(Struct *);
+ virtual void visit(Array *);
+ virtual void visit(Blob *);
+ virtual void visit(Pointer *);
+
+protected:
+ inline void _visit(Value *value) {
+ if (value) {
+ value->visit(*this);
+ }
+ }
+};
+
+
+inline std::ostream & operator <<(std::ostream &os, Value *value) {
+ if (value) {
+ value->dump(os);
+ }
+ return os;
+}
+
+
+class Call
+{
+public:
+ unsigned no;
+ const FunctionSig *sig;
+ std::vector<Value *> args;
+ Value *ret;
+
+ Call(FunctionSig *_sig) : sig(_sig), args(_sig->num_args), ret(0) { }
+ ~Call();
+
+ inline const char * name(void) const {
+ return sig->name;
+ }
+
+ inline Value & arg(unsigned index) {
+ assert(index < args.size());
+ return *(args[index]);
+ }
+
+ void dump(std::ostream &os, bool color=true);
+};
+
+
+inline std::ostream & operator <<(std::ostream &os, Call &call) {
+ call.dump(os);
+ return os;
+}
+
+
+} /* namespace Trace */
+
+#endif /* _TRACE_MODEL_HPP_ */
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * 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.
+ *
+ **************************************************************************/
+
+
+#include "trace_writer.hpp"
+
+
+namespace Trace {
+
+
+class ModelWriter : public Visitor
+{
+protected:
+ Writer &writer;
+
+public:
+ ModelWriter(Writer &_writer) :
+ writer(_writer) {
+ }
+
+ void visit(Null *) {
+ writer.writeNull();
+ }
+
+ void visit(Bool *node) {
+ writer.writeBool(node->value);
+ }
+
+ void visit(SInt *node) {
+ writer.writeSInt(node->value);
+ }
+
+ void visit(UInt *node) {
+ writer.writeUInt(node->value);
+ }
+
+ void visit(Float *node) {
+ writer.writeFloat(node->value);
+ }
+
+ void visit(String *node) {
+ writer.writeString(node->value);
+ }
+
+ void visit(Enum *node) {
+ writer.writeEnum(node->sig);
+ }
+
+ void visit(Bitmask *node) {
+ writer.writeBitmask(node->sig, node->value);
+ }
+
+ void visit(Struct *node) {
+ writer.beginStruct(node->sig);
+ for (unsigned i = 0; i < node->sig->num_members; ++i) {
+ _visit(node->members[i]);
+ }
+ writer.endStruct();
+ }
+
+ void visit(Array *node) {
+ writer.beginArray(node->values.size());
+ for (std::vector<Value *>::iterator it = node->values.begin(); it != node->values.end(); ++it) {
+ _visit(*it);
+ }
+ writer.endArray();
+ }
+
+ void visit(Blob *node) {
+ writer.writeBlob(node->buf, node->size);
+ }
+
+ void visit(Pointer *node) {
+ writer.writeOpaque((const void *) (size_t) node->value);
+ }
+
+ void visit(Call *call) {
+ unsigned call_no = writer.beginEnter(call->sig);
+ for (unsigned i = 0; i < call->args.size(); ++i) {
+ if (call->args[i]) {
+ writer.beginArg(i);
+ _visit(call->args[i]);
+ writer.endArg();
+ }
+ }
+ writer.endEnter();
+ writer.beginLeave(call_no);
+ if (call->ret) {
+ writer.beginReturn();
+ _visit(call->ret);
+ writer.endReturn();
+ }
+ writer.endLeave();
+ }
+};
+
+
+void Writer::writeCall(Call *call) {
+ ModelWriter visitor(*this);
+ visitor.visit(call);
+}
+
+
+} /* namespace Trace */
+
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * Copyright 2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "trace_file.hpp"
+#include "trace_snappyfile.hpp"
+#include "trace_parser.hpp"
+
+
+#define TRACE_VERBOSE 0
+
+
+namespace Trace {
+
+
+Parser::Parser() {
+ file = NULL;
+ next_call_no = 0;
+ version = 0;
+}
+
+
+Parser::~Parser() {
+ close();
+}
+
+
+bool Parser::open(const char *filename) {
+ assert(!file);
+ if (File::isZLibCompressed(filename)) {
+ file = new ZLibFile;
+ } else {
+ file = new SnappyFile;
+ }
+
+ if (!file->open(filename, File::Read)) {
+ return false;
+ }
+
+ version = read_uint();
+ if (version > TRACE_VERSION) {
+ std::cerr << "error: unsupported trace format version " << version << "\n";
+ return false;
+ }
+
+ return true;
+}
+
+template <typename Iter>
+inline void
+deleteAll(Iter begin, Iter end)
+{
+ while (begin != end) {
+ delete *begin;
+ ++begin;
+ }
+}
+
+template <typename Container>
+inline void
+deleteAll(Container &c)
+{
+ deleteAll(c.begin(), c.end());
+ c.clear();
+}
+
+void Parser::close(void) {
+ if (file) {
+ file->close();
+ delete file;
+ file = NULL;
+ }
+
+ deleteAll(calls);
+
+ // Delete all signature data. Signatures are mere structures which don't
+ // own their own memory, so we need to destroy all data we created here.
+
+ for (FunctionMap::iterator it = functions.begin(); it != functions.end(); ++it) {
+ FunctionSigState *sig = *it;
+ if (sig) {
+ delete [] sig->name;
+ for (unsigned arg = 0; arg < sig->num_args; ++arg) {
+ delete [] sig->arg_names[arg];
+ }
+ delete [] sig->arg_names;
+ delete sig;
+ }
+ }
+ functions.clear();
+
+ for (StructMap::iterator it = structs.begin(); it != structs.end(); ++it) {
+ StructSigState *sig = *it;
+ if (sig) {
+ delete [] sig->name;
+ for (unsigned member = 0; member < sig->num_members; ++member) {
+ delete [] sig->member_names[member];
+ }
+ delete [] sig->member_names;
+ delete sig;
+ }
+ }
+ structs.clear();
+
+ for (EnumMap::iterator it = enums.begin(); it != enums.end(); ++it) {
+ EnumSigState *sig = *it;
+ if (sig) {
+ delete [] sig->name;
+ delete sig;
+ }
+ }
+ enums.clear();
+
+ for (BitmaskMap::iterator it = bitmasks.begin(); it != bitmasks.end(); ++it) {
+ BitmaskSigState *sig = *it;
+ if (sig) {
+ for (unsigned flag = 0; flag < sig->num_flags; ++flag) {
+ delete [] sig->flags[flag].name;
+ }
+ delete [] sig->flags;
+ delete sig;
+ }
+ }
+ bitmasks.clear();
+}
+
+
+void Parser::getBookmark(ParseBookmark &bookmark) {
+ bookmark.offset = file->currentOffset();
+ bookmark.next_call_no = next_call_no;
+}
+
+
+void Parser::setBookmark(const ParseBookmark &bookmark) {
+ file->setCurrentOffset(bookmark.offset);
+ next_call_no = bookmark.next_call_no;
+
+ // Simply ignore all pending calls
+ deleteAll(calls);
+}
+
+
+Call *Parser::parse_call(Mode mode) {
+ do {
+ int c = read_byte();
+ switch(c) {
+ case Trace::EVENT_ENTER:
+ parse_enter(mode);
+ break;
+ case Trace::EVENT_LEAVE:
+ return parse_leave(mode);
+ default:
+ std::cerr << "error: unknown event " << c << "\n";
+ exit(1);
+ case -1:
+ for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
+ std::cerr << "warning: incomplete call " << (*it)->name() << "\n";
+ std::cerr << **it << "\n";
+ }
+ return NULL;
+ }
+ } while(true);
+}
+
+
+/**
+ * Helper function to lookup an ID in a vector, resizing the vector if it doesn't fit.
+ */
+template<class T>
+T *lookup(std::vector<T *> &map, size_t index) {
+ if (index >= map.size()) {
+ map.resize(index + 1);
+ return NULL;
+ } else {
+ return map[index];
+ }
+}
+
+
+FunctionSig *Parser::parse_function_sig(void) {
+ size_t id = read_uint();
+
+ FunctionSigState *sig = lookup(functions, id);
+
+ if (!sig) {
+ /* parse the signature */
+ sig = new FunctionSigState;
+ sig->id = id;
+ sig->name = read_string();
+ sig->num_args = read_uint();
+ const char **arg_names = new const char *[sig->num_args];
+ for (unsigned i = 0; i < sig->num_args; ++i) {
+ arg_names[i] = read_string();
+ }
+ sig->arg_names = arg_names;
+ sig->offset = file->currentOffset();
+ functions[id] = sig;
+ } else if (file->currentOffset() < sig->offset) {
+ /* skip over the signature */
+ skip_string(); /* name */
+ int num_args = read_uint();
+ for (unsigned i = 0; i < num_args; ++i) {
+ skip_string(); /*arg_name*/
+ }
+ }
+
+ assert(sig);
+ return sig;
+}
+
+
+StructSig *Parser::parse_struct_sig() {
+ size_t id = read_uint();
+
+ StructSigState *sig = lookup(structs, id);
+
+ if (!sig) {
+ /* parse the signature */
+ sig = new StructSigState;
+ sig->id = id;
+ sig->name = read_string();
+ sig->num_members = read_uint();
+ const char **member_names = new const char *[sig->num_members];
+ for (unsigned i = 0; i < sig->num_members; ++i) {
+ member_names[i] = read_string();
+ }
+ sig->member_names = member_names;
+ sig->offset = file->currentOffset();
+ structs[id] = sig;
+ } else if (file->currentOffset() < sig->offset) {
+ /* skip over the signature */
+ skip_string(); /* name */
+ unsigned num_members = read_uint();
+ for (unsigned i = 0; i < num_members; ++i) {
+ skip_string(); /* member_name */
+ }
+ }
+
+ assert(sig);
+ return sig;
+}
+
+
+EnumSig *Parser::parse_enum_sig() {
+ size_t id = read_uint();
+
+ EnumSigState *sig = lookup(enums, id);
+
+ if (!sig) {
+ /* parse the signature */
+ sig = new EnumSigState;
+ sig->id = id;
+ sig->name = read_string();
+ Value *value = parse_value();
+ sig->value = value->toSInt();
+ delete value;
+ sig->offset = file->currentOffset();
+ enums[id] = sig;
+ } else if (file->currentOffset() < sig->offset) {
+ /* skip over the signature */
+ skip_string(); /*name*/
+ scan_value();
+ }
+
+ assert(sig);
+ return sig;
+}
+
+
+BitmaskSig *Parser::parse_bitmask_sig() {
+ size_t id = read_uint();
+
+ BitmaskSigState *sig = lookup(bitmasks, id);
+
+ if (!sig) {
+ /* parse the signature */
+ sig = new BitmaskSigState;
+ sig->id = id;
+ sig->num_flags = read_uint();
+ BitmaskFlag *flags = new BitmaskFlag[sig->num_flags];
+ for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) {
+ it->name = read_string();
+ it->value = read_uint();
+ if (it->value == 0 && it != flags) {
+ std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n";
+ }
+ }
+ sig->flags = flags;
+ sig->offset = file->currentOffset();
+ bitmasks[id] = sig;
+ } else if (file->currentOffset() < sig->offset) {
+ /* skip over the signature */
+ int num_flags = read_uint();
+ for (int i = 0; i < num_flags; ++i) {
+ skip_string(); /*name */
+ skip_uint(); /* value */
+ }
+ }
+
+ assert(sig);
+ return sig;
+}
+
+
+void Parser::parse_enter(Mode mode) {
+ FunctionSig *sig = parse_function_sig();
+
+ Call *call = new Call(sig);
+
+ call->no = next_call_no++;
+
+ if (parse_call_details(call, mode)) {
+ calls.push_back(call);
+ } else {
+ delete call;
+ }
+}
+
+
+Call *Parser::parse_leave(Mode mode) {
+ unsigned call_no = read_uint();
+ Call *call = NULL;
+ for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
+ if ((*it)->no == call_no) {
+ call = *it;
+ calls.erase(it);
+ break;
+ }
+ }
+ if (!call) {
+ return NULL;
+ }
+
+ if (parse_call_details(call, mode)) {
+ return call;
+ } else {
+ delete call;
+ return NULL;
+ }
+}
+
+
+bool Parser::parse_call_details(Call *call, Mode mode) {
+ do {
+ int c = read_byte();
+ switch(c) {
+ case Trace::CALL_END:
+ return true;
+ case Trace::CALL_ARG:
+ parse_arg(call, mode);
+ break;
+ case Trace::CALL_RET:
+ call->ret = parse_value(mode);
+ break;
+ default:
+ std::cerr << "error: ("<<call->name()<< ") unknown call detail "
+ << c << "\n";
+ exit(1);
+ case -1:
+ return false;
+ }
+ } while(true);
+}
+
+
+void Parser::parse_arg(Call *call, Mode mode) {
+ unsigned index = read_uint();
+ Value *value = parse_value(mode);
+ if (value) {
+ if (index >= call->args.size()) {
+ call->args.resize(index + 1);
+ }
+ call->args[index] = value;
+ }
+}
+
+
+Value *Parser::parse_value(void) {
+ int c;
+ Value *value;
+ c = read_byte();
+ switch(c) {
+ case Trace::TYPE_NULL:
+ value = new Null;
+ break;
+ case Trace::TYPE_FALSE:
+ value = new Bool(false);
+ break;
+ case Trace::TYPE_TRUE:
+ value = new Bool(true);
+ break;
+ case Trace::TYPE_SINT:
+ value = parse_sint();
+ break;
+ case Trace::TYPE_UINT:
+ value = parse_uint();
+ break;
+ case Trace::TYPE_FLOAT:
+ value = parse_float();
+ break;
+ case Trace::TYPE_DOUBLE:
+ value = parse_double();
+ break;
+ case Trace::TYPE_STRING:
+ value = parse_string();
+ break;
+ case Trace::TYPE_ENUM:
+ value = parse_enum();
+ break;
+ case Trace::TYPE_BITMASK:
+ value = parse_bitmask();
+ break;
+ case Trace::TYPE_ARRAY:
+ value = parse_array();
+ break;
+ case Trace::TYPE_STRUCT:
+ value = parse_struct();
+ break;
+ case Trace::TYPE_BLOB:
+ value = parse_blob();
+ break;
+ case Trace::TYPE_OPAQUE:
+ value = parse_opaque();
+ break;
+ default:
+ std::cerr << "error: unknown type " << c << "\n";
+ exit(1);
+ case -1:
+ value = NULL;
+ break;
+ }
+#if TRACE_VERBOSE
+ if (value) {
+ std::cerr << "\tVALUE " << value << "\n";
+ }
+#endif
+ return value;
+}
+
+
+void Parser::scan_value(void) {
+ int c = read_byte();
+ switch(c) {
+ case Trace::TYPE_NULL:
+ case Trace::TYPE_FALSE:
+ case Trace::TYPE_TRUE:
+ break;
+ case Trace::TYPE_SINT:
+ scan_sint();
+ break;
+ case Trace::TYPE_UINT:
+ scan_uint();
+ break;
+ case Trace::TYPE_FLOAT:
+ scan_float();
+ break;
+ case Trace::TYPE_DOUBLE:
+ scan_double();
+ break;
+ case Trace::TYPE_STRING:
+ scan_string();
+ break;
+ case Trace::TYPE_ENUM:
+ scan_enum();
+ break;
+ case Trace::TYPE_BITMASK:
+ scan_bitmask();
+ break;
+ case Trace::TYPE_ARRAY:
+ scan_array();
+ break;
+ case Trace::TYPE_STRUCT:
+ scan_struct();
+ break;
+ case Trace::TYPE_BLOB:
+ scan_blob();
+ break;
+ case Trace::TYPE_OPAQUE:
+ scan_opaque();
+ break;
+ default:
+ std::cerr << "error: unknown type " << c << "\n";
+ exit(1);
+ case -1:
+ break;
+ }
+}
+
+
+Value *Parser::parse_sint() {
+ return new SInt(-(signed long long)read_uint());
+}
+
+
+void Parser::scan_sint() {
+ skip_uint();
+}
+
+
+Value *Parser::parse_uint() {
+ return new UInt(read_uint());
+}
+
+
+void Parser::scan_uint() {
+ skip_uint();
+}
+
+
+Value *Parser::parse_float() {
+ float value;
+ file->read(&value, sizeof value);
+ return new Float(value);
+}
+
+
+void Parser::scan_float() {
+ file->skip(sizeof(float));
+}
+
+
+Value *Parser::parse_double() {
+ double value;
+ file->read(&value, sizeof value);
+ return new Float(value);
+}
+
+
+void Parser::scan_double() {
+ file->skip(sizeof(double));
+}
+
+
+Value *Parser::parse_string() {
+ return new String(read_string());
+}
+
+
+void Parser::scan_string() {
+ skip_string();
+}
+
+
+Value *Parser::parse_enum() {
+ EnumSig *sig = parse_enum_sig();
+ return new Enum(sig);
+}
+
+
+void Parser::scan_enum() {
+ parse_enum_sig();
+}
+
+
+Value *Parser::parse_bitmask() {
+ BitmaskSig *sig = parse_bitmask_sig();
+
+ unsigned long long value = read_uint();
+
+ return new Bitmask(sig, value);
+}
+
+
+void Parser::scan_bitmask() {
+ parse_bitmask_sig();
+ skip_uint(); /* value */
+}
+
+
+Value *Parser::parse_array(void) {
+ size_t len = read_uint();
+ Array *array = new Array(len);
+ for (size_t i = 0; i < len; ++i) {
+ array->values[i] = parse_value();
+ }
+ return array;
+}
+
+
+void Parser::scan_array(void) {
+ size_t len = read_uint();
+ for (size_t i = 0; i < len; ++i) {
+ scan_value();
+ }
+}
+
+
+Value *Parser::parse_blob(void) {
+ size_t size = read_uint();
+ Blob *blob = new Blob(size);
+ if (size) {
+ file->read(blob->buf, (unsigned)size);
+ }
+ return blob;
+}
+
+
+void Parser::scan_blob(void) {
+ size_t size = read_uint();
+ if (size) {
+ file->skip(size);
+ }
+}
+
+
+Value *Parser::parse_struct() {
+ StructSig *sig = parse_struct_sig();
+ Struct *value = new Struct(sig);
+
+ for (size_t i = 0; i < sig->num_members; ++i) {
+ value->members[i] = parse_value();
+ }
+
+ return value;
+}
+
+
+void Parser::scan_struct() {
+ StructSig *sig = parse_struct_sig();
+ for (size_t i = 0; i < sig->num_members; ++i) {
+ scan_value();
+ }
+}
+
+
+Value *Parser::parse_opaque() {
+ unsigned long long addr;
+ addr = read_uint();
+ return new Pointer(addr);
+}
+
+
+void Parser::scan_opaque() {
+ skip_uint();
+}
+
+
+const char * Parser::read_string(void) {
+ size_t len = read_uint();
+ char * value = new char[len + 1];
+ if (len) {
+ file->read(value, (unsigned)len);
+ }
+ value[len] = 0;
+#if TRACE_VERBOSE
+ std::cerr << "\tSTRING \"" << value << "\"\n";
+#endif
+ return value;
+}
+
+
+void Parser::skip_string(void) {
+ size_t len = read_uint();
+ file->skip(len);
+}
+
+
+unsigned long long Parser::read_uint(void) {
+ unsigned long long value = 0;
+ int c;
+ unsigned shift = 0;
+ do {
+ c = file->getc();
+ if (c == -1) {
+ break;
+ }
+ value |= (unsigned long long)(c & 0x7f) << shift;
+ shift += 7;
+ } while(c & 0x80);
+#if TRACE_VERBOSE
+ std::cerr << "\tUINT " << value << "\n";
+#endif
+ return value;
+}
+
+
+void Parser::skip_uint(void) {
+ int c;
+ do {
+ c = file->getc();
+ if (c == -1) {
+ break;
+ }
+ } while(c & 0x80);
+}
+
+
+inline int Parser::read_byte(void) {
+ int c = file->getc();
+#if TRACE_VERBOSE
+ if (c < 0)
+ std::cerr << "\tEOF" << "\n";
+ else
+ std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
+#endif
+ return c;
+}
+
+
+inline void Parser::skip_byte(void) {
+ file->skip(1);
+}
+
+
+} /* namespace Trace */
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+#ifndef _TRACE_PARSER_HPP_
+#define _TRACE_PARSER_HPP_
+
+
+#include <iostream>
+#include <list>
+
+#include "trace_file.hpp"
+#include "trace_format.hpp"
+#include "trace_model.hpp"
+
+
+namespace Trace {
+
+
+struct ParseBookmark
+{
+ File::Offset offset;
+ unsigned next_call_no;
+};
+
+
+class Parser
+{
+protected:
+ File *file;
+
+ enum Mode {
+ FULL = 0,
+ SCAN,
+ SKIP
+ };
+
+ typedef std::list<Call *> CallList;
+ CallList calls;
+
+ // Helper template that extends a base signature structure, with additional
+ // parsing information.
+ template< class T >
+ struct SigState : public T {
+ // Offset in the file of where signature was defined. It is used when
+ // reparsing to determine whether the signature definition is to be
+ // expected next or not.
+ File::Offset offset;
+ };
+
+ typedef SigState<FunctionSig> FunctionSigState;
+ typedef SigState<StructSig> StructSigState;
+ typedef SigState<EnumSig> EnumSigState;
+ typedef SigState<BitmaskSig> BitmaskSigState;
+
+ typedef std::vector<FunctionSigState *> FunctionMap;
+ typedef std::vector<StructSigState *> StructMap;
+ typedef std::vector<EnumSigState *> EnumMap;
+ typedef std::vector<BitmaskSigState *> BitmaskMap;
+
+ FunctionMap functions;
+ StructMap structs;
+ EnumMap enums;
+ BitmaskMap bitmasks;
+
+ unsigned next_call_no;
+
+public:
+ unsigned long long version;
+
+ Parser();
+
+ ~Parser();
+
+ bool open(const char *filename);
+
+ void close(void);
+
+ Call *parse_call(void) {
+ return parse_call(FULL);
+ }
+
+ bool supportsOffsets() const
+ {
+ return file->supportsOffsets();
+ }
+
+ void getBookmark(ParseBookmark &bookmark);
+
+ void setBookmark(const ParseBookmark &bookmark);
+
+ int percentRead()
+ {
+ return file->percentRead();
+ }
+
+ Call *scan_call() {
+ return parse_call(SCAN);
+ }
+
+protected:
+ Call *parse_call(Mode mode);
+
+ FunctionSig *parse_function_sig(void);
+ StructSig *parse_struct_sig();
+ EnumSig *parse_enum_sig();
+ BitmaskSig *parse_bitmask_sig();
+
+ Call *parse_Call(Mode mode);
+
+ void parse_enter(Mode mode);
+
+ Call *parse_leave(Mode mode);
+
+ bool parse_call_details(Call *call, Mode mode);
+
+ void parse_arg(Call *call, Mode mode);
+
+ Value *parse_value(void);
+ void scan_value(void);
+ inline Value *parse_value(Mode mode) {
+ if (mode == FULL) {
+ return parse_value();
+ } else {
+ scan_value();
+ return NULL;
+ }
+ }
+
+ Value *parse_sint();
+ void scan_sint();
+
+ Value *parse_uint();
+ void scan_uint();
+
+ Value *parse_float();
+ void scan_float();
+
+ Value *parse_double();
+ void scan_double();
+
+ Value *parse_string();
+ void scan_string();
+
+ Value *parse_enum();
+ void scan_enum();
+
+ Value *parse_bitmask();
+ void scan_bitmask();
+
+ Value *parse_array(void);
+ void scan_array(void);
+
+ Value *parse_blob(void);
+ void scan_blob(void);
+
+ Value *parse_struct();
+ void scan_struct();
+
+ Value *parse_opaque();
+ void scan_opaque();
+
+ const char * read_string(void);
+ void skip_string(void);
+
+ unsigned long long read_uint(void);
+ void skip_uint(void);
+
+ inline int read_byte(void);
+ inline void skip_byte(void);
+};
+
+
+} /* namespace Trace */
+
+#endif /* _TRACE_PARSER_HPP_ */
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2011 Zack Rusin
+ * 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.
+ *
+ **************************************************************************/
+
+
+#include "trace_snappyfile.hpp"
+
+#include <snappy.h>
+
+#include <iostream>
+
+#include <assert.h>
+#include <string.h>
+
+using namespace Trace;
+
+/*
+ * Snappy file format.
+ * -------------------
+ *
+ * Snappy at its core is just a compressoin algorithm so we're
+ * creating a new file format which uses snappy compression
+ * to hold the trace data.
+ *
+ * The file is composed of a number of chunks, they are:
+ * chunk {
+ * uint32 - specifying the length of the compressed data
+ * compressed data, in little endian
+ * }
+ * File can contain any number of such chunks.
+ * The default size of an uncompressed chunk is specified in
+ * SNAPPY_CHUNK_SIZE.
+ *
+ * Note:
+ * Currently the default size for a a to-be-compressed data is
+ * 1mb, meaning that the compressed data will be <= 1mb.
+ * The reason it's 1mb is because it seems
+ * to offer a pretty good compression/disk io speed ratio
+ * but that might change.
+ *
+ */
+
+SnappyFile::SnappyFile(const std::string &filename,
+ File::Mode mode)
+ : File(),
+ m_cache(0),
+ m_cachePtr(0),
+ m_cacheSize(0)
+{
+ size_t maxCompressedLength =
+ snappy::MaxCompressedLength(SNAPPY_CHUNK_SIZE);
+ m_compressedCache = new char[maxCompressedLength];
+}
+
+SnappyFile::~SnappyFile()
+{
+ delete [] m_compressedCache;
+ delete [] m_cache;
+}
+
+bool SnappyFile::rawOpen(const std::string &filename, File::Mode mode)
+{
+ std::ios_base::openmode fmode = std::fstream::binary;
+ if (mode == File::Write) {
+ fmode |= (std::fstream::out | std::fstream::trunc);
+ createCache(SNAPPY_CHUNK_SIZE);
+ } else if (mode == File::Read) {
+ fmode |= std::fstream::in;
+ }
+
+ m_stream.open(filename.c_str(), fmode);
+
+ //read in the initial buffer if we're reading
+ if (m_stream.is_open() && mode == File::Read) {
+ m_stream.seekg(0, std::ios::end);
+ m_endPos = m_stream.tellg();
+ m_stream.seekg(0, std::ios::beg);
+
+ // read the snappy file identifier
+ unsigned char byte1, byte2;
+ m_stream >> byte1;
+ m_stream >> byte2;
+ assert(byte1 == SNAPPY_BYTE1 && byte2 == SNAPPY_BYTE2);
+
+ flushReadCache();
+ } else if (m_stream.is_open() && mode == File::Write) {
+ // write the snappy file identifier
+ m_stream << SNAPPY_BYTE1;
+ m_stream << SNAPPY_BYTE2;
+ }
+ return m_stream.is_open();
+}
+
+bool SnappyFile::rawWrite(const void *buffer, size_t length)
+{
+ if (freeCacheSize() > length) {
+ memcpy(m_cachePtr, buffer, length);
+ m_cachePtr += length;
+ } else if (freeCacheSize() == length) {
+ memcpy(m_cachePtr, buffer, length);
+ m_cachePtr += length;
+ flushWriteCache();
+ } else {
+ int sizeToWrite = length;
+
+ while (sizeToWrite >= freeCacheSize()) {
+ int endSize = freeCacheSize();
+ int offset = length - sizeToWrite;
+ memcpy(m_cachePtr, (const char*)buffer + offset, endSize);
+ sizeToWrite -= endSize;
+ m_cachePtr += endSize;
+ flushWriteCache();
+ }
+ if (sizeToWrite) {
+ int offset = length - sizeToWrite;
+ memcpy(m_cachePtr, (const char*)buffer + offset, sizeToWrite);
+ m_cachePtr += sizeToWrite;
+ }
+ }
+
+ return true;
+}
+
+bool SnappyFile::rawRead(void *buffer, size_t length)
+{
+ if (endOfData()) {
+ return false;
+ }
+
+ if (freeCacheSize() >= length) {
+ memcpy(buffer, m_cachePtr, length);
+ m_cachePtr += length;
+ } else {
+ size_t sizeToRead = length;
+ size_t offset = 0;
+ while (sizeToRead) {
+ size_t chunkSize = std::min(freeCacheSize(), sizeToRead);
+ offset = length - sizeToRead;
+ memcpy((char*)buffer + offset, m_cachePtr, chunkSize);
+ m_cachePtr += chunkSize;
+ sizeToRead -= chunkSize;
+ if (sizeToRead > 0) {
+ flushReadCache();
+ }
+ if (!m_cacheSize) {
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+int SnappyFile::rawGetc()
+{
+ int c = 0;
+ if (!rawRead(&c, 1))
+ return -1;
+ return c;
+}
+
+void SnappyFile::rawClose()
+{
+ if (m_mode == File::Write) {
+ flushWriteCache();
+ }
+ m_stream.close();
+ delete [] m_cache;
+ m_cache = NULL;
+ m_cachePtr = NULL;
+}
+
+void SnappyFile::rawFlush()
+{
+ assert(m_mode == File::Write);
+ flushWriteCache();
+ m_stream.flush();
+}
+
+void SnappyFile::flushWriteCache()
+{
+ size_t inputLength = usedCacheSize();
+
+ if (inputLength) {
+ size_t compressedLength;
+
+ ::snappy::RawCompress(m_cache, inputLength,
+ m_compressedCache, &compressedLength);
+
+ writeCompressedLength(compressedLength);
+ m_stream.write(m_compressedCache, compressedLength);
+ m_cachePtr = m_cache;
+ }
+ assert(m_cachePtr == m_cache);
+}
+
+void SnappyFile::flushReadCache(size_t skipLength)
+{
+ //assert(m_cachePtr == m_cache + m_cacheSize);
+ m_currentOffset.chunk = m_stream.tellg();
+ size_t compressedLength;
+ compressedLength = readCompressedLength();
+
+ if (compressedLength) {
+ m_stream.read((char*)m_compressedCache, compressedLength);
+ ::snappy::GetUncompressedLength(m_compressedCache, compressedLength,
+ &m_cacheSize);
+ createCache(m_cacheSize);
+ if (skipLength < m_cacheSize) {
+ ::snappy::RawUncompress(m_compressedCache, compressedLength,
+ m_cache);
+ }
+ } else {
+ createCache(0);
+ }
+}
+
+void SnappyFile::createCache(size_t size)
+{
+ // TODO: only re-allocate if the current buffer is not big enough
+
+ if (m_cache) {
+ delete [] m_cache;
+ }
+
+ if (size) {
+ m_cache = new char[size];
+ } else {
+ m_cache = NULL;
+ }
+
+ m_cachePtr = m_cache;
+ m_cacheSize = size;
+}
+
+void SnappyFile::writeCompressedLength(size_t length)
+{
+ unsigned char buf[4];
+ buf[0] = length & 0xff; length >>= 8;
+ buf[1] = length & 0xff; length >>= 8;
+ buf[2] = length & 0xff; length >>= 8;
+ buf[3] = length & 0xff; length >>= 8;
+ assert(length == 0);
+ m_stream.write((const char *)buf, sizeof buf);
+}
+
+size_t SnappyFile::readCompressedLength()
+{
+ unsigned char buf[4];
+ size_t length;
+ m_stream.read((char *)buf, sizeof buf);
+ if (m_stream.fail()) {
+ length = 0;
+ } else {
+ length = (size_t)buf[0];
+ length |= ((size_t)buf[1] << 8);
+ length |= ((size_t)buf[2] << 16);
+ length |= ((size_t)buf[3] << 24);
+ }
+ return length;
+}
+
+bool SnappyFile::supportsOffsets() const
+{
+ return true;
+}
+
+File::Offset SnappyFile::currentOffset()
+{
+ m_currentOffset.offsetInChunk = m_cachePtr - m_cache;
+ return m_currentOffset;
+}
+
+void SnappyFile::setCurrentOffset(const File::Offset &offset)
+{
+ // to remove eof bit
+ m_stream.clear();
+ // seek to the start of a chunk
+ m_stream.seekg(offset.chunk, std::ios::beg);
+ // load the chunk
+ flushReadCache();
+ assert(m_cacheSize >= offset.offsetInChunk);
+ // seek within our cache to the correct location within the chunk
+ m_cachePtr = m_cache + offset.offsetInChunk;
+
+}
+
+bool SnappyFile::rawSkip(size_t length)
+{
+ if (endOfData()) {
+ return false;
+ }
+
+ if (freeCacheSize() >= length) {
+ m_cachePtr += length;
+ } else {
+ size_t sizeToRead = length;
+ while (sizeToRead) {
+ size_t chunkSize = std::min(freeCacheSize(), sizeToRead);
+ m_cachePtr += chunkSize;
+ sizeToRead -= chunkSize;
+ if (sizeToRead > 0) {
+ flushReadCache(sizeToRead);
+ }
+ if (!m_cacheSize) {
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+int SnappyFile::rawPercentRead()
+{
+ return 100 * (double(m_stream.tellg()) / double(m_endPos));
+}
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2011 Zack Rusin
+ * 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.
+ *
+ **************************************************************************/
+
+
+#ifndef TRACE_SNAPPYFILE_HPP
+#define TRACE_SNAPPYFILE_HPP
+
+#include <assert.h>
+
+#include "trace_file.hpp"
+
+#include <string>
+#include <fstream>
+
+namespace snappy {
+ class File;
+}
+
+namespace Trace {
+
+#define SNAPPY_CHUNK_SIZE (1 * 1024 * 1024)
+
+#define SNAPPY_BYTE1 'a'
+#define SNAPPY_BYTE2 't'
+
+
+class SnappyFile : public File {
+public:
+ SnappyFile(const std::string &filename = std::string(),
+ File::Mode mode = File::Read);
+ virtual ~SnappyFile();
+
+ virtual bool supportsOffsets() const;
+ virtual File::Offset currentOffset();
+ virtual void setCurrentOffset(const File::Offset &offset);
+protected:
+ virtual bool rawOpen(const std::string &filename, File::Mode mode);
+ virtual bool rawWrite(const void *buffer, size_t length);
+ virtual bool rawRead(void *buffer, size_t length);
+ virtual int rawGetc();
+ virtual void rawClose();
+ virtual void rawFlush();
+ virtual bool rawSkip(size_t length);
+ virtual int rawPercentRead();
+
+private:
+ inline size_t usedCacheSize() const
+ {
+ assert(m_cachePtr >= m_cache);
+ return m_cachePtr - m_cache;
+ }
+ inline size_t freeCacheSize() const
+ {
+ assert(m_cacheSize >= usedCacheSize());
+ if (m_cacheSize > 0) {
+ return m_cacheSize - usedCacheSize();
+ } else {
+ return 0;
+ }
+ }
+ inline bool endOfData() const
+ {
+ return m_stream.eof() && freeCacheSize() == 0;
+ }
+ void flushWriteCache();
+ void flushReadCache(size_t skipLength = 0);
+ void createCache(size_t size);
+ void writeCompressedLength(size_t length);
+ size_t readCompressedLength();
+private:
+ std::fstream m_stream;
+ char *m_cache;
+ char *m_cachePtr;
+ size_t m_cacheSize;
+
+ char *m_compressedCache;
+
+ File::Offset m_currentOffset;
+ std::streampos m_endPos;
+};
+
+}
+
+#endif // TRACE_SNAPPYFILE_HPP
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2007-2009 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "os.hpp"
+#include "trace_writer.hpp"
+#include "trace_snappyfile.hpp"
+#include "trace_format.hpp"
+
+
+namespace Trace {
+
+
+Writer::Writer() :
+ call_no(0)
+{
+ m_file = new Trace::SnappyFile;
+ close();
+}
+
+Writer::~Writer()
+{
+ close();
+ delete m_file;
+ m_file = NULL;
+}
+
+void
+Writer::close(void) {
+ m_file->close();
+}
+
+bool
+Writer::open(const char *filename) {
+ close();
+
+ if (!m_file->open(filename, File::Write)) {
+ return false;
+ }
+
+ call_no = 0;
+ functions.clear();
+ structs.clear();
+ enums.clear();
+ bitmasks.clear();
+
+ _writeUInt(TRACE_VERSION);
+
+ return true;
+}
+
+void inline
+Writer::_write(const void *sBuffer, size_t dwBytesToWrite) {
+ m_file->write(sBuffer, dwBytesToWrite);
+}
+
+void inline
+Writer::_writeByte(char c) {
+ _write(&c, 1);
+}
+
+void inline
+Writer::_writeUInt(unsigned long long value) {
+ char buf[2 * sizeof value];
+ unsigned len;
+
+ len = 0;
+ do {
+ assert(len < sizeof buf);
+ buf[len] = 0x80 | (value & 0x7f);
+ value >>= 7;
+ ++len;
+ } while (value);
+
+ assert(len);
+ buf[len - 1] &= 0x7f;
+
+ _write(buf, len);
+}
+
+void inline
+Writer::_writeFloat(float value) {
+ assert(sizeof value == 4);
+ _write((const char *)&value, sizeof value);
+}
+
+void inline
+Writer::_writeDouble(double value) {
+ assert(sizeof value == 8);
+ _write((const char *)&value, sizeof value);
+}
+
+void inline
+Writer::_writeString(const char *str) {
+ size_t len = strlen(str);
+ _writeUInt(len);
+ _write(str, len);
+}
+
+inline bool lookup(std::vector<bool> &map, size_t index) {
+ if (index >= map.size()) {
+ map.resize(index + 1);
+ return false;
+ } else {
+ return map[index];
+ }
+}
+
+unsigned Writer::beginEnter(const FunctionSig *sig) {
+ _writeByte(Trace::EVENT_ENTER);
+ _writeUInt(sig->id);
+ if (!lookup(functions, sig->id)) {
+ _writeString(sig->name);
+ _writeUInt(sig->num_args);
+ for (unsigned i = 0; i < sig->num_args; ++i) {
+ _writeString(sig->arg_names[i]);
+ }
+ functions[sig->id] = true;
+ }
+
+ return call_no++;
+}
+
+void Writer::endEnter(void) {
+ _writeByte(Trace::CALL_END);
+}
+
+void Writer::beginLeave(unsigned call) {
+ _writeByte(Trace::EVENT_LEAVE);
+ _writeUInt(call);
+}
+
+void Writer::endLeave(void) {
+ _writeByte(Trace::CALL_END);
+}
+
+void Writer::beginArg(unsigned index) {
+ _writeByte(Trace::CALL_ARG);
+ _writeUInt(index);
+}
+
+void Writer::beginReturn(void) {
+ _writeByte(Trace::CALL_RET);
+}
+
+void Writer::beginArray(size_t length) {
+ _writeByte(Trace::TYPE_ARRAY);
+ _writeUInt(length);
+}
+
+void Writer::beginStruct(const StructSig *sig) {
+ _writeByte(Trace::TYPE_STRUCT);
+ _writeUInt(sig->id);
+ if (!lookup(structs, sig->id)) {
+ _writeString(sig->name);
+ _writeUInt(sig->num_members);
+ for (unsigned i = 0; i < sig->num_members; ++i) {
+ _writeString(sig->member_names[i]);
+ }
+ structs[sig->id] = true;
+ }
+}
+
+void Writer::writeBool(bool value) {
+ _writeByte(value ? Trace::TYPE_TRUE : Trace::TYPE_FALSE);
+}
+
+void Writer::writeSInt(signed long long value) {
+ if (value < 0) {
+ _writeByte(Trace::TYPE_SINT);
+ _writeUInt(-value);
+ } else {
+ _writeByte(Trace::TYPE_UINT);
+ _writeUInt(value);
+ }
+}
+
+void Writer::writeUInt(unsigned long long value) {
+ _writeByte(Trace::TYPE_UINT);
+ _writeUInt(value);
+}
+
+void Writer::writeFloat(float value) {
+ _writeByte(Trace::TYPE_FLOAT);
+ _writeFloat(value);
+}
+
+void Writer::writeDouble(double value) {
+ _writeByte(Trace::TYPE_DOUBLE);
+ _writeDouble(value);
+}
+
+void Writer::writeString(const char *str) {
+ if (!str) {
+ Writer::writeNull();
+ return;
+ }
+ _writeByte(Trace::TYPE_STRING);
+ _writeString(str);
+}
+
+void Writer::writeString(const char *str, size_t len) {
+ if (!str) {
+ Writer::writeNull();
+ return;
+ }
+ _writeByte(Trace::TYPE_STRING);
+ _writeUInt(len);
+ _write(str, len);
+}
+
+void Writer::writeWString(const wchar_t *str) {
+ if (!str) {
+ Writer::writeNull();
+ return;
+ }
+ _writeByte(Trace::TYPE_STRING);
+ _writeString("<wide-string>");
+}
+
+void Writer::writeBlob(const void *data, size_t size) {
+ if (!data) {
+ Writer::writeNull();
+ return;
+ }
+ _writeByte(Trace::TYPE_BLOB);
+ _writeUInt(size);
+ if (size) {
+ _write(data, size);
+ }
+}
+
+void Writer::writeEnum(const EnumSig *sig) {
+ _writeByte(Trace::TYPE_ENUM);
+ _writeUInt(sig->id);
+ if (!lookup(enums, sig->id)) {
+ _writeString(sig->name);
+ Writer::writeSInt(sig->value);
+ enums[sig->id] = true;
+ }
+}
+
+void Writer::writeBitmask(const BitmaskSig *sig, unsigned long long value) {
+ _writeByte(Trace::TYPE_BITMASK);
+ _writeUInt(sig->id);
+ if (!lookup(bitmasks, sig->id)) {
+ _writeUInt(sig->num_flags);
+ for (unsigned i = 0; i < sig->num_flags; ++i) {
+ if (i != 0 && sig->flags[i].value == 0) {
+ OS::DebugMessage("apitrace: warning: sig %s is zero but is not first flag\n", sig->flags[i].name);
+ }
+ _writeString(sig->flags[i].name);
+ _writeUInt(sig->flags[i].value);
+ }
+ bitmasks[sig->id] = true;
+ }
+ _writeUInt(value);
+}
+
+void Writer::writeNull(void) {
+ _writeByte(Trace::TYPE_NULL);
+}
+
+void Writer::writeOpaque(const void *addr) {
+ if (!addr) {
+ Writer::writeNull();
+ return;
+ }
+ _writeByte(Trace::TYPE_OPAQUE);
+ _writeUInt((size_t)addr);
+}
+
+
+} /* namespace Trace */
+
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2007-2010 VMware, Inc.
+ * 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.
+ *
+ **************************************************************************/
+
+/*
+ * Trace writing functions.
+ */
+
+#ifndef _TRACE_WRITER_HPP_
+#define _TRACE_WRITER_HPP_
+
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "trace_model.hpp"
+
+
+namespace Trace {
+ class File;
+
+ class Writer {
+ protected:
+ File *m_file;
+ unsigned call_no;
+
+ std::vector<bool> functions;
+ std::vector<bool> structs;
+ std::vector<bool> enums;
+ std::vector<bool> bitmasks;
+
+ public:
+ Writer();
+ ~Writer();
+
+ bool open(const char *filename);
+ void close(void);
+
+ unsigned beginEnter(const FunctionSig *sig);
+ void endEnter(void);
+
+ void beginLeave(unsigned call);
+ void endLeave(void);
+
+ void beginArg(unsigned index);
+ inline void endArg(void) {}
+
+ void beginReturn(void);
+ inline void endReturn(void) {}
+
+ void beginArray(size_t length);
+ inline void endArray(void) {}
+
+ inline void beginElement(void) {}
+ inline void endElement(void) {}
+
+ void beginStruct(const StructSig *sig);
+ inline void endStruct(void) {}
+
+ void writeBool(bool value);
+ void writeSInt(signed long long value);
+ void writeUInt(unsigned long long value);
+ void writeFloat(float value);
+ void writeDouble(double value);
+ void writeString(const char *str);
+ void writeString(const char *str, size_t size);
+ void writeWString(const wchar_t *str);
+ void writeBlob(const void *data, size_t size);
+ void writeEnum(const EnumSig *sig);
+ void writeBitmask(const BitmaskSig *sig, unsigned long long value);
+ void writeNull(void);
+ void writeOpaque(const void *ptr);
+
+ void writeCall(Call *call);
+
+ protected:
+ void inline _write(const void *sBuffer, size_t dwBytesToWrite);
+ void inline _writeByte(char c);
+ void inline _writeUInt(unsigned long long value);
+ void inline _writeFloat(float value);
+ void inline _writeDouble(double value);
+ void inline _writeString(const char *str);
+
+ };
+
+ /**
+ * A specialized Writer class, mean to trace the current process.
+ *
+ * In particular:
+ * - it creates a trace file based on the current process name
+ * - uses mutexes to allow tracing from multiple threades
+ * - flushes the output to ensure the last call is traced in event of
+ * abnormal termination
+ */
+ class LocalWriter : public Writer {
+ protected:
+ int acquired;
+
+ public:
+ /**
+ * Should never called directly -- use localWriter singleton below instead.
+ */
+ LocalWriter();
+ ~LocalWriter();
+
+ void open(void);
+
+ unsigned beginEnter(const FunctionSig *sig);
+ void endEnter(void);
+
+ void beginLeave(unsigned call);
+ void endLeave(void);
+
+ void flush(void);
+ };
+
+ /**
+ * Singleton.
+ */
+ extern LocalWriter localWriter;
+}
+
+#endif /* _TRACE_WRITER_HPP_ */
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-/*
- * Helpers for coloring output.
- */
-
-#ifndef _FORMATTER_HPP_
-#define _FORMATTER_HPP_
-
-
-#include <iostream>
-
-
-namespace Formatter {
-
-/*
- * See also http://bytes.com/topic/c/answers/63822-design-question-little-c-header-colorizing-text-linux-comments-ideas
- */
-
-class Attribute {
-public:
- virtual ~Attribute() {}
-
- virtual void apply(std::ostream &) const {}
-};
-
-
-enum Color {
- RED,
- GREEN,
- BLUE,
-};
-
-
-class Formatter {
-public:
- virtual ~Formatter() {}
-
- virtual Attribute *normal(void) const { return new Attribute; }
- virtual Attribute *bold(void) const { return new Attribute; }
- virtual Attribute *italic(void) const { return new Attribute; }
- virtual Attribute *color(Color) const { return new Attribute; }
-};
-
-
-class AnsiAttribute : public Attribute {
-protected:
- const char *escape;
-public:
- AnsiAttribute(const char *_escape) : escape(_escape) {}
- void apply(std::ostream& os) const {
- os << "\33[" << escape;
- }
-};
-
-
-/**
- * Formatter for plain-text files which outputs ANSI escape codes. See
- * http://en.wikipedia.org/wiki/ANSI_escape_code for more information
- * concerning ANSI escape codes.
- */
-class AnsiFormatter : public Formatter {
-protected:
-public:
- virtual Attribute *normal(void) const { return new AnsiAttribute("0m"); }
- virtual Attribute *bold(void) const { return new AnsiAttribute("1m"); }
- virtual Attribute *italic(void) const { return new AnsiAttribute("3m"); }
- virtual Attribute *color(Color c) const {
- static const char *color_escapes[] = {
- "31m", /* red */
- "32m", /* green */
- "34m", /* blue */
- };
- return new AnsiAttribute(color_escapes[c]);
- }
-};
-
-
-inline std::ostream& operator<<(std::ostream& os, const Attribute *attr) {
- attr->apply(os);
- return os;
-}
-
-
-#ifdef _WIN32
-
-#include <windows.h>
-
-class WindowsAttribute : public Attribute {
-protected:
- WORD wAttributes;
-public:
- WindowsAttribute(WORD _wAttributes) : wAttributes(_wAttributes) {}
- void apply(std::ostream& os) const {
- DWORD nStdHandleOutput;
- if (os == std::cout) {
- nStdHandleOutput = STD_OUTPUT_HANDLE;
- } else if (os == std::cerr) {
- nStdHandleOutput = STD_ERROR_HANDLE;
- } else {
- return;
- }
- HANDLE hConsoleOutput = GetStdHandle(nStdHandleOutput);
- if (hConsoleOutput == INVALID_HANDLE_VALUE) {
- return;
- }
-
- SetConsoleTextAttribute(hConsoleOutput, wAttributes);
- }
-};
-
-
-/**
- * Formatter for the Windows Console.
- */
-class WindowsFormatter : public Formatter {
-protected:
-public:
- virtual Attribute *normal(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); }
- virtual Attribute *bold(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY); }
- virtual Attribute *italic(void) const { return new WindowsAttribute(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); }
- virtual Attribute *color(Color c) const {
- static const WORD color_escapes[] = {
- FOREGROUND_RED | FOREGROUND_INTENSITY,
- FOREGROUND_GREEN | FOREGROUND_INTENSITY,
- FOREGROUND_BLUE | FOREGROUND_INTENSITY,
- };
- return new WindowsAttribute(color_escapes[c]);
- }
-};
-
-#endif
-
-
-inline Formatter *defaultFormatter(bool color = true) {
- if (color) {
-#ifdef _WIN32
- return new WindowsFormatter;
-#else
- return new AnsiFormatter;
-#endif
- } else {
- return new Formatter;
- }
-}
-
-
-} /* namespace Formatter */
-
-
-#endif /* _FORMATTER_HPP_ */
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * Copyright 2008-2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-
-#include <assert.h>
-#include <math.h>
-
-#include "image.hpp"
-
-
-namespace Image {
-
-
-double Image::compare(Image &ref)
-{
- if (width != ref.width ||
- height != ref.height ||
- channels != ref.channels) {
- return 0.0;
- }
-
- const unsigned char *pSrc = start();
- const unsigned char *pRef = ref.start();
-
- assert(channels >= 3);
-
- unsigned long long error = 0;
- for (unsigned y = 0; y < height; ++y) {
- for (unsigned x = 0; x < width; ++x) {
- // FIXME: Ignore alpha channel until we are able to pick a visual
- // that matches the traces
- for (unsigned c = 0; c < 3; ++c) {
- int delta = pSrc[x*channels + c] - pRef[x*channels + c];
- error += delta*delta;
- }
- }
-
- pSrc += stride();
- pRef += ref.stride();
- }
-
- double numerator = error*2 + 1;
- double denominator = height*width*3ULL*255ULL*255ULL*2;
- double quotient = numerator/denominator;
-
- // Precision in bits
- double precision = -log(quotient)/log(2.0);
-
- return precision;
-}
-
-
-} /* namespace Image */
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2008-2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-/*
- * Image I/O.
- */
-
-#ifndef _IMAGE_HPP_
-#define _IMAGE_HPP_
-
-
-#include <fstream>
-
-
-namespace Image {
-
-
-class Image {
-public:
- unsigned width;
- unsigned height;
- unsigned channels;
-
- // Flipped vertically or not
- bool flipped;
-
- // Pixels in RGBA format
- unsigned char *pixels;
-
- inline Image(unsigned w, unsigned h, unsigned c = 4, bool f = false) :
- width(w),
- height(h),
- channels(c),
- flipped(f),
- pixels(new unsigned char[h*w*c])
- {}
-
- inline ~Image() {
- delete [] pixels;
- }
-
- inline unsigned char *start(void) {
- return flipped ? pixels + (height - 1)*width*channels : pixels;
- }
-
- inline const unsigned char *start(void) const {
- return flipped ? pixels + (height - 1)*width*channels : pixels;
- }
-
- inline unsigned char *end(void) {
- return flipped ? pixels - width*channels : pixels + height*width*channels;
- }
-
- inline const unsigned char *end(void) const {
- return flipped ? pixels - width*channels : pixels + height*width*channels;
- }
-
- inline signed stride(void) const {
- return flipped ? -width*channels : width*channels;
- }
-
- bool writeBMP(const char *filename) const;
-
- void writePNM(std::ostream &os, const char *comment = NULL) const;
-
- inline bool writePNM(const char *filename, const char *comment = NULL) const {
- std::ofstream os(filename, std::ofstream::binary);
- if (!os) {
- return false;
- }
- writePNM(os, comment);
- return true;
- }
-
- bool writePNG(const char *filename) const;
-
- double compare(Image &ref);
-};
-
-bool writePixelsToBuffer(unsigned char *pixels,
- unsigned w, unsigned h, unsigned numChannels,
- bool flipped,
- char **buffer,
- int *size);
-
-Image *
-readPNG(const char *filename);
-
-
-} /* namespace Image */
-
-
-#endif /* _IMAGE_HPP_ */
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * Copyright 2008-2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-
-#include <assert.h>
-#include <stdint.h>
-
-#include "image.hpp"
-
-
-namespace Image {
-
-
-#pragma pack(push,2)
-struct FileHeader {
- uint16_t bfType;
- uint32_t bfSize;
- uint16_t bfReserved1;
- uint16_t bfReserved2;
- uint32_t bfOffBits;
-};
-#pragma pack(pop)
-
-struct InfoHeader {
- uint32_t biSize;
- int32_t biWidth;
- int32_t biHeight;
- uint16_t biPlanes;
- uint16_t biBitCount;
- uint32_t biCompression;
- uint32_t biSizeImage;
- int32_t biXPelsPerMeter;
- int32_t biYPelsPerMeter;
- uint32_t biClrUsed;
- uint32_t biClrImportant;
-};
-
-struct Pixel {
- uint8_t rgbBlue;
- uint8_t rgbGreen;
- uint8_t rgbRed;
- uint8_t rgbAlpha;
-};
-
-
-bool
-Image::writeBMP(const char *filename) const {
- assert(channels == 4);
-
- struct FileHeader bmfh;
- struct InfoHeader bmih;
- unsigned x, y;
-
- bmfh.bfType = 0x4d42;
- bmfh.bfSize = 14 + 40 + height*width*4;
- bmfh.bfReserved1 = 0;
- bmfh.bfReserved2 = 0;
- bmfh.bfOffBits = 14 + 40;
-
- bmih.biSize = 40;
- bmih.biWidth = width;
- bmih.biHeight = height;
- bmih.biPlanes = 1;
- bmih.biBitCount = 32;
- bmih.biCompression = 0;
- bmih.biSizeImage = height*width*4;
- bmih.biXPelsPerMeter = 0;
- bmih.biYPelsPerMeter = 0;
- bmih.biClrUsed = 0;
- bmih.biClrImportant = 0;
-
- std::ofstream stream(filename, std::ofstream::binary);
-
- if (!stream) {
- return false;
- }
-
- stream.write((const char *)&bmfh, 14);
- stream.write((const char *)&bmih, 40);
-
- unsigned stride = width*4;
-
- if (flipped) {
- for (y = 0; y < height; ++y) {
- const unsigned char *ptr = pixels + y * stride;
- for (x = 0; x < width; ++x) {
- struct Pixel pixel;
- pixel.rgbRed = ptr[x*4 + 0];
- pixel.rgbGreen = ptr[x*4 + 1];
- pixel.rgbBlue = ptr[x*4 + 2];
- pixel.rgbAlpha = ptr[x*4 + 3];
- stream.write((const char *)&pixel, 4);
- }
- }
- } else {
- y = height;
- while (y--) {
- const unsigned char *ptr = pixels + y * stride;
- for (x = 0; x < width; ++x) {
- struct Pixel pixel;
- pixel.rgbRed = ptr[x*4 + 0];
- pixel.rgbGreen = ptr[x*4 + 1];
- pixel.rgbBlue = ptr[x*4 + 2];
- pixel.rgbAlpha = ptr[x*4 + 3];
- stream.write((const char *)&pixel, 4);
- }
- }
- }
-
- stream.close();
-
- return true;
-}
-
-
-} /* namespace Image */
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * Copyright 2008-2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-
-#include <zlib.h>
-#include <png.h>
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <fstream>
-
-#include "image.hpp"
-
-
-namespace Image {
-
-
-bool
-Image::writePNG(const char *filename) const {
- FILE *fp;
- png_structp png_ptr;
- png_infop info_ptr;
-
- fp = fopen(filename, "wb");
- if (!fp)
- goto no_fp;
-
- png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (!png_ptr)
- goto no_png;
-
- info_ptr = png_create_info_struct(png_ptr);
- if (!info_ptr) {
- png_destroy_write_struct(&png_ptr, NULL);
- goto no_png;
- }
-
- if (setjmp(png_jmpbuf(png_ptr))) {
- png_destroy_write_struct(&png_ptr, &info_ptr);
- goto no_png;
- }
-
- png_init_io(png_ptr, fp);
-
- int color_type;
- switch (channels) {
- case 4:
- color_type = PNG_COLOR_TYPE_RGB_ALPHA;
- break;
- case 3:
- color_type = PNG_COLOR_TYPE_RGB;
- break;
- case 2:
- color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
- break;
- case 1:
- color_type = PNG_COLOR_TYPE_GRAY;
- break;
- default:
- assert(0);
- return false;
- }
-
- png_set_IHDR(png_ptr, info_ptr, width, height, 8, color_type,
- PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
-
- png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
-
- png_write_info(png_ptr, info_ptr);
-
- if (!flipped) {
- for (unsigned y = 0; y < height; ++y) {
- png_bytep row = (png_bytep)(pixels + y*width*channels);
- png_write_rows(png_ptr, &row, 1);
- }
- } else {
- unsigned y = height;
- while (y--) {
- png_bytep row = (png_bytep)(pixels + y*width*channels);
- png_write_rows(png_ptr, &row, 1);
- }
- }
-
- png_write_end(png_ptr, info_ptr);
- png_destroy_write_struct(&png_ptr, &info_ptr);
-
- fclose(fp);
- return true;
-
-no_png:
- fclose(fp);
-no_fp:
- return false;
-}
-
-
-Image *
-readPNG(const char *filename)
-{
- FILE *fp;
- png_structp png_ptr;
- png_infop info_ptr;
- png_infop end_info;
- Image *image;
-
- fp = fopen(filename, "rb");
- if (!fp)
- goto no_fp;
-
- png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (!png_ptr)
- goto no_png;
-
- info_ptr = png_create_info_struct(png_ptr);
- if (!info_ptr) {
- png_destroy_read_struct(&png_ptr, NULL, NULL);
- goto no_png;
- }
-
- end_info = png_create_info_struct(png_ptr);
- if (!end_info) {
- png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
- goto no_png;
- }
-
- if (setjmp(png_jmpbuf(png_ptr))) {
- png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
- goto no_png;
- }
-
- png_init_io(png_ptr, fp);
-
- png_read_info(png_ptr, info_ptr);
-
- png_uint_32 width, height;
- int bit_depth, color_type, interlace_type, compression_type, filter_method;
-
- png_get_IHDR(png_ptr, info_ptr,
- &width, &height,
- &bit_depth, &color_type, &interlace_type,
- &compression_type, &filter_method);
-
- image = new Image(width, height);
- if (!image)
- goto no_image;
-
- /* Convert to RGBA8 */
- if (color_type == PNG_COLOR_TYPE_PALETTE)
- png_set_palette_to_rgb(png_ptr);
- if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
- png_set_expand_gray_1_2_4_to_8(png_ptr);
- if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
- png_set_tRNS_to_alpha(png_ptr);
- if (bit_depth == 16)
- png_set_strip_16(png_ptr);
-
- for (unsigned y = 0; y < height; ++y) {
- png_bytep row = (png_bytep)(image->pixels + y*width*4);
- png_read_row(png_ptr, row, NULL);
- }
-
- png_read_end(png_ptr, info_ptr);
- png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
- fclose(fp);
- return image;
-
-no_image:
- png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
-no_png:
- fclose(fp);
-no_fp:
- return NULL;
-}
-
-
-struct png_tmp_buffer
-{
- char *buffer;
- size_t size;
-};
-
-static void
-pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length)
-{
- struct png_tmp_buffer *buf = (struct png_tmp_buffer*) png_get_io_ptr(png_ptr);
- size_t nsize = buf->size + length;
-
- /* allocate or grow buffer */
- if (buf->buffer)
- buf->buffer = (char*)realloc(buf->buffer, nsize);
- else
- buf->buffer = (char*)malloc(nsize);
-
- if (!buf->buffer)
- png_error(png_ptr, "Buffer allocation error");
-
- memcpy(buf->buffer + buf->size, data, length);
- buf->size += length;
-}
-
-bool writePixelsToBuffer(unsigned char *pixels,
- unsigned width, unsigned height, unsigned numChannels,
- bool flipped,
- char **buffer,
- int *size)
-{
- struct png_tmp_buffer png_mem;
- png_structp png_ptr;
- png_infop info_ptr;
- int type;
-
- png_mem.buffer = NULL;
- png_mem.size = 0;
-
- switch (numChannels) {
- case 4:
- type = PNG_COLOR_TYPE_RGB_ALPHA;
- break;
- case 3:
- type = PNG_COLOR_TYPE_RGB;
- break;
- case 2:
- type = PNG_COLOR_TYPE_GRAY_ALPHA;
- break;
- case 1:
- type = PNG_COLOR_TYPE_GRAY;
- break;
- default:
- goto no_png;
- }
-
- png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (!png_ptr)
- goto no_png;
-
- info_ptr = png_create_info_struct(png_ptr);
- if (!info_ptr) {
- png_destroy_write_struct(&png_ptr, NULL);
- goto no_png;
- }
-
- if (setjmp(png_jmpbuf(png_ptr))) {
- png_destroy_write_struct(&png_ptr, &info_ptr);
- goto no_png;
- }
-
- png_set_write_fn(png_ptr, &png_mem, pngWriteCallback, NULL);
-
- png_set_IHDR(png_ptr, info_ptr, width, height, 8,
- type, PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
-
- png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
-
- png_write_info(png_ptr, info_ptr);
-
- if (!flipped) {
- for (unsigned y = 0; y < height; ++y) {
- png_bytep row = (png_bytep)(pixels + y*width*numChannels);
- png_write_rows(png_ptr, &row, 1);
- }
- } else {
- unsigned y = height;
- while (y--) {
- png_bytep row = (png_bytep)(pixels + y*width*numChannels);
- png_write_rows(png_ptr, &row, 1);
- }
- }
-
- png_write_end(png_ptr, info_ptr);
- png_destroy_write_struct(&png_ptr, &info_ptr);
-
- *buffer = png_mem.buffer;
- *size = png_mem.size;
-
- return true;
-
-no_png:
- *buffer = NULL;
- *size = 0;
-
- if (png_mem.buffer)
- free(png_mem.buffer);
- return false;
-}
-
-} /* namespace Image */
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * Copyright 2008-2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-
-#include <assert.h>
-#include <string.h>
-#include <stdint.h>
-
-#include "image.hpp"
-
-
-namespace Image {
-
-/**
- * http://en.wikipedia.org/wiki/Netpbm_format
- * http://netpbm.sourceforge.net/doc/ppm.html
- */
-void
-Image::writePNM(std::ostream &os, const char *comment) const {
- assert(channels == 1 || channels >= 3);
-
- os << (channels == 1 ? "P5" : "P6") << "\n";
- if (comment) {
- os << "#" << comment << "\n";
- }
- os << width << " " << height << "\n";
- os << "255" << "\n";
-
- const unsigned char *row;
-
- if (channels == 1 || channels == 3) {
- for (row = start(); row != end(); row += stride()) {
- os.write((const char *)row, width*channels);
- }
- } else {
- unsigned char *tmp = new unsigned char[width*3];
- if (channels == 4) {
- for (row = start(); row != end(); row += stride()) {
- const uint32_t *src = (const uint32_t *)row;
- uint32_t *dst = (uint32_t *)tmp;
- unsigned x;
- for (x = 0; x + 4 <= width; x += 4) {
- /*
- * It's much faster to access dwords than bytes.
- *
- * FIXME: Big-endian version.
- */
-
- uint32_t rgba0 = *src++ & 0xffffff;
- uint32_t rgba1 = *src++ & 0xffffff;
- uint32_t rgba2 = *src++ & 0xffffff;
- uint32_t rgba3 = *src++ & 0xffffff;
- uint32_t rgb0 = rgba0
- | (rgba1 << 24);
- uint32_t rgb1 = (rgba1 >> 8)
- | (rgba2 << 16);
- uint32_t rgb2 = (rgba2 >> 16)
- | (rgba3 << 8);
- *dst++ = rgb0;
- *dst++ = rgb1;
- *dst++ = rgb2;
- }
- for (; x < width; ++x) {
- tmp[x*3 + 0] = row[x*4 + 0];
- tmp[x*3 + 1] = row[x*4 + 1];
- tmp[x*3 + 2] = row[x*4 + 2];
- }
- os.write((const char *)tmp, width*3);
- }
- } else if (channels == 2) {
- for (row = start(); row != end(); row += stride()) {
- const unsigned char *src = row;
- unsigned char *dst = tmp;
- for (unsigned x = 0; x < width; ++x) {
- *dst++ = *src++;
- *dst++ = *src++;
- *dst++ = 0;
- }
- os.write((const char *)tmp, width*3);
- }
- } else {
- assert(0);
- }
- delete [] tmp;
- }
-}
-
-
-} /* namespace Image */
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * 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.
- *
- **************************************************************************/
-
-/*
- * Trace writing functions.
- */
-
-#ifndef _JSON_HPP_
-#define _JSON_HPP_
-
-#include <assert.h>
-#include <stddef.h>
-#include <wchar.h>
-
-#include <iomanip>
-#include <ostream>
-#include <string>
-
-
-class JSONWriter
-{
-private:
- std::ostream &os;
-
- int level;
- bool value;
- char space;
-
- void newline(void) {
- os << "\n";
- for (int i = 0; i < level; ++i)
- os << " ";
- }
-
- void separator(void) {
- if (value) {
- os << ",";
- switch (space) {
- case '\0':
- break;
- case '\n':
- newline();
- break;
- default:
- os << space;
- break;
- }
- } else {
- if (space == '\n') {
- newline();
- }
- }
- }
-
- void escapeAsciiString(const char *str) {
- os << "\"";
-
- const unsigned char *src = (const unsigned char *)str;
- unsigned char c;
- while ((c = *src++)) {
- if ((c == '\"') ||
- (c == '\\')) {
- // escape character
- os << '\\' << (unsigned char)c;
- } else if ((c >= 0x20 && c <= 0x7e) ||
- c == '\t' ||
- c == '\r' ||
- c == '\n') {
- // pass-through character
- os << (unsigned char)c;
- } else {
- assert(0);
- os << "?";
- }
- }
-
- os << "\"";
- }
-
- void escapeUnicodeString(const char *str) {
- os << "\"";
-
- const char *locale = setlocale(LC_CTYPE, "");
- const char *src = str;
- mbstate_t state;
-
- memset(&state, 0, sizeof state);
-
- do {
- // Convert characters one at a time in order to recover from
- // conversion errors
- wchar_t c;
- size_t written = mbsrtowcs(&c, &src, 1, &state);
- if (written == 0) {
- // completed
- break;
- } if (written == (size_t)-1) {
- // conversion error -- skip
- os << "?";
- do {
- ++src;
- } while (*src & 0x80);
- } else if ((c == '\"') ||
- (c == '\\')) {
- // escape character
- os << '\\' << (unsigned char)c;
- } else if ((c >= 0x20 && c <= 0x7e) ||
- c == '\t' ||
- c == '\r' ||
- c == '\n') {
- // pass-through character
- os << (unsigned char)c;
- } else {
- // unicode
- os << "\\u" << std::setfill('0') << std::hex << std::setw(4) << (unsigned)c;
- os << std::dec;
- }
- } while (src);
-
- setlocale(LC_CTYPE, locale);
-
- os << "\"";
- }
-
- void encodeBase64String(const unsigned char *bytes, size_t size) {
- const char *table64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- unsigned char c0, c1, c2, c3;
- char buf[4];
- unsigned written;
-
- os << "\"";
-
- written = 0;
- while (size >= 3) {
- c0 = bytes[0] >> 2;
- c1 = ((bytes[0] & 0x03) << 4) | ((bytes[1] & 0xf0) >> 4);
- c2 = ((bytes[1] & 0x0f) << 2) | ((bytes[2] & 0xc0) >> 6);
- c3 = bytes[2] & 0x3f;
-
- buf[0] = table64[c0];
- buf[1] = table64[c1];
- buf[2] = table64[c2];
- buf[3] = table64[c3];
-
- os.write(buf, 4);
-
- bytes += 3;
- size -= 3;
- ++written;
-
- if (written >= 76/4 && size) {
- os << "\n";
- written = 0;
- }
- }
-
- if (size > 0) {
- c0 = bytes[0] >> 2;
- c1 = ((bytes[0] & 0x03) << 4);
- buf[2] = '=';
- buf[3] = '=';
-
- if (size > 1) {
- c1 |= ((bytes[1] & 0xf0) >> 4);
- c2 = ((bytes[1] & 0x0f) << 2);
- if (size > 2) {
- c2 |= ((bytes[2] & 0xc0) >> 6);
- c3 = bytes[2] & 0x3f;
- buf[3] = table64[c3];
- }
- buf[2] = table64[c2];
- }
- buf[1] = table64[c1];
- buf[0] = table64[c0];
-
- os.write(buf, 4);
- }
-
- os << "\"";
- }
-
-public:
- JSONWriter(std::ostream &_os) :
- os(_os),
- level(0),
- value(false),
- space(0)
- {
- beginObject();
- }
-
- ~JSONWriter() {
- endObject();
- newline();
- }
-
- inline void beginObject() {
- separator();
- os << "{";
- ++level;
- value = false;
- }
-
- inline void endObject() {
- --level;
- if (value)
- newline();
- os << "}";
- value = true;
- space = '\n';
- }
-
- inline void beginMember(const char * name) {
- space = 0;
- separator();
- newline();
- escapeAsciiString(name);
- os << ": ";
- value = false;
- }
-
- inline void beginMember(const std::string &name) {
- beginMember(name.c_str());
- }
-
- inline void endMember(void) {
- assert(value);
- value = true;
- space = 0;
- }
-
- inline void beginArray() {
- separator();
- os << "[";
- ++level;
- value = false;
- space = 0;
- }
-
- inline void endArray(void) {
- --level;
- if (space == '\n') {
- newline();
- }
- os << "]";
- value = true;
- space = '\n';
- }
-
- inline void writeString(const char *s) {
- separator();
- escapeUnicodeString(s);
- value = true;
- space = ' ';
- }
-
- inline void writeString(const std::string &s) {
- writeString(s.c_str());
- }
-
- inline void writeBase64(const void *bytes, size_t size) {
- separator();
- encodeBase64String((const unsigned char *)bytes, size);
- value = true;
- space = ' ';
- }
-
- inline void writeNull(void) {
- separator();
- os << "null";
- value = true;
- space = ' ';
- }
-
- inline void writeBool(bool b) {
- separator();
- os << (b ? "true" : "false");
- value = true;
- space = ' ';
- }
-
- template<class T>
- inline void writeNumber(T n) {
- if (n != n) {
- // NaN
- writeNull();
- } else {
- separator();
- os << std::dec << std::setprecision(9) << n;
- value = true;
- space = ' ';
- }
- }
-
- inline void writeStringMember(const char *name, const char *s) {
- beginMember(name);
- writeString(s);
- endMember();
- }
-
- inline void writeBoolMember(const char *name, bool b) {
- beginMember(name);
- writeBool(b);
- endMember();
- }
-
- template<class T>
- inline void writeNumberMember(const char *name, T n) {
- beginMember(name);
- writeNumber(n);
- endMember();
- }
-};
-
-#endif /* _JSON_HPP_ */
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-/*
- * Simple OS abstraction layer.
- */
-
-#ifndef _OS_HPP_
-#define _OS_HPP_
-
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-
-#ifdef _WIN32
-#ifndef snprintf
-#define snprintf _snprintf
-#endif
-#ifndef vsnprintf
-#define vsnprintf _vsnprintf
-#endif
-#define PATH_SEP '\\'
-#else /* !_WIN32 */
-#define PATH_SEP '/'
-#endif /* !_WIN32 */
-
-#ifndef PATH_MAX
-#define PATH_MAX 1024
-#endif
-
-namespace OS {
-
-void AcquireMutex(void);
-
-void ReleaseMutex(void);
-
-bool GetProcessName(char *str, size_t size);
-bool GetCurrentDir(char *str, size_t size);
-
-void DebugMessage(const char *format, ...)
-#ifdef __GNUC__
- __attribute__ ((format (printf, 1, 2)))
-#endif
-;
-
-#if defined _WIN32 || defined __CYGWIN__
- /* We always use .def files on windows for now */
- #if 0
- #define PUBLIC __declspec(dllexport)
- #else
- #define PUBLIC
- #endif
- #define PRIVATE
-#else
- #if __GNUC__ >= 4
- #define PUBLIC __attribute__ ((visibility("default")))
- #define PRIVATE __attribute__ ((visibility("hidden")))
- #else
- #define PUBLIC
- #define PRIVATE
- #endif
-#endif
-
-/**
- * Get the current time in microseconds from an unknown base.
- */
-long long GetTime(void);
-
-void Abort(void);
-
-void SetExceptionCallback(void (*callback)(void));
-void ResetExceptionCallback(void);
-
-} /* namespace OS */
-
-#endif /* _OS_HPP_ */
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2010-2011 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-
-#include <assert.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <unistd.h>
-#include <sys/time.h>
-#include <pthread.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <signal.h>
-
-#ifdef __APPLE__
-#include <mach-o/dyld.h>
-#endif
-
-#include "os.hpp"
-
-
-namespace OS {
-
-
-static pthread_mutex_t
-mutex = PTHREAD_MUTEX_INITIALIZER;
-
-
-void
-AcquireMutex(void)
-{
- pthread_mutex_lock(&mutex);
-}
-
-
-void
-ReleaseMutex(void)
-{
- pthread_mutex_unlock(&mutex);
-}
-
-
-bool
-GetProcessName(char *str, size_t size)
-{
- char szProcessPath[PATH_MAX + 1];
- char *lpProcessName;
-
- // http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
-#ifdef __APPLE__
- uint32_t len = sizeof szProcessPath;
- if (_NSGetExecutablePath(szProcessPath, &len) != 0) {
- *str = 0;
- return false;
- }
-#else
- ssize_t len;
- len = readlink("/proc/self/exe", szProcessPath, sizeof(szProcessPath) - 1);
- if (len == -1) {
- // /proc/self/exe is not available on setuid processes, so fallback to
- // /proc/self/cmdline.
- int fd = open("/proc/self/cmdline", O_RDONLY);
- if (fd >= 0) {
- len = read(fd, szProcessPath, sizeof(szProcessPath) - 1);
- close(fd);
- }
- }
- if (len <= 0) {
- snprintf(str, size, "%i", (int)getpid());
- return true;
- }
-#endif
- szProcessPath[len] = 0;
-
- lpProcessName = strrchr(szProcessPath, '/');
- lpProcessName = lpProcessName ? lpProcessName + 1 : szProcessPath;
-
- strncpy(str, lpProcessName, size);
- if (size)
- str[size - 1] = 0;
-
- return true;
-}
-
-bool
-GetCurrentDir(char *str, size_t size)
-{
- char *ret;
- ret = getcwd(str, size);
- str[size - 1] = 0;
- return ret ? true : false;
-}
-
-void
-DebugMessage(const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- fflush(stdout);
- vfprintf(stderr, format, ap);
- va_end(ap);
-}
-
-long long GetTime(void)
-{
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return tv.tv_usec + tv.tv_sec*1000000LL;
-}
-
-void
-Abort(void)
-{
- exit(0);
-}
-
-
-static void (*gCallback)(void) = NULL;
-
-#define NUM_SIGNALS 16
-
-struct sigaction old_actions[NUM_SIGNALS];
-
-
-/*
- * See also:
- * - http://sourceware.org/git/?p=glibc.git;a=blob;f=debug/segfault.c
- * - http://ggi.cvs.sourceforge.net/viewvc/ggi/ggi-core/libgg/gg/cleanup.c?view=markup
- */
-static void signal_handler(int sig, siginfo_t *info, void *context)
-{
- static int recursion_count = 0;
-
- fprintf(stderr, "signal_handler: sig = %i\n", sig);
-
- if (recursion_count) {
- fprintf(stderr, "recursion with sig %i\n", sig);
- } else {
- if (gCallback) {
- ++recursion_count;
- gCallback();
- --recursion_count;
- }
- }
-
- struct sigaction *old_action;
- if (sig >= NUM_SIGNALS) {
- /* This should never happen */
- fprintf(stderr, "Unexpected signal %i\n", sig);
- raise(SIGKILL);
- }
- old_action = &old_actions[sig];
-
- if (old_action->sa_flags & SA_SIGINFO) {
- // Handler is in sa_sigaction
- old_action->sa_sigaction(sig, info, context);
- } else {
- if (old_action->sa_handler == SIG_DFL) {
- fprintf(stderr, "taking default action for signal %i\n", sig);
-
-#if 1
- struct sigaction dfl_action;
- dfl_action.sa_handler = SIG_DFL;
- sigemptyset (&dfl_action.sa_mask);
- dfl_action.sa_flags = 0;
- sigaction(sig, &dfl_action, NULL);
-
- raise(sig);
-#else
- raise(SIGKILL);
-#endif
- } else if (old_action->sa_handler == SIG_IGN) {
- /* ignore */
- } else {
- /* dispatch to handler */
- old_action->sa_handler(sig);
- }
- }
-}
-
-void
-SetExceptionCallback(void (*callback)(void))
-{
- assert(!gCallback);
- if (!gCallback) {
- gCallback = callback;
-
- struct sigaction new_action;
- new_action.sa_sigaction = signal_handler;
- sigemptyset(&new_action.sa_mask);
- new_action.sa_flags = SA_SIGINFO | SA_RESTART;
-
-
- for (int sig = 1; sig < NUM_SIGNALS; ++sig) {
- // SIGKILL and SIGSTOP can't be handled
- if (sig != SIGKILL && sig != SIGSTOP) {
- if (sigaction(sig, NULL, &old_actions[sig]) >= 0) {
- sigaction(sig, &new_action, NULL);
- }
- }
- }
- }
-}
-
-void
-ResetExceptionCallback(void)
-{
- gCallback = NULL;
-}
-
-} /* namespace OS */
-
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-#include <windows.h>
-#include <assert.h>
-#include <signal.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "os.hpp"
-
-
-namespace OS {
-
-
-/*
- * Trick from http://locklessinc.com/articles/pthreads_on_windows/
- */
-static CRITICAL_SECTION
-CriticalSection = {
- (PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 0
-};
-
-
-void
-AcquireMutex(void)
-{
- EnterCriticalSection(&CriticalSection);
-}
-
-
-void
-ReleaseMutex(void)
-{
- LeaveCriticalSection(&CriticalSection);
-}
-
-
-bool
-GetProcessName(char *str, size_t size)
-{
- char szProcessPath[PATH_MAX];
- char *lpProcessName;
- char *lpProcessExt;
-
- GetModuleFileNameA(NULL, szProcessPath, sizeof(szProcessPath)/sizeof(szProcessPath[0]));
-
- lpProcessName = strrchr(szProcessPath, '\\');
- lpProcessName = lpProcessName ? lpProcessName + 1 : szProcessPath;
-
- lpProcessExt = strrchr(lpProcessName, '.');
- if (lpProcessExt) {
- *lpProcessExt = '\0';
- }
-
- strncpy(str, lpProcessName, size);
-
- return true;
-}
-
-bool
-GetCurrentDir(char *str, size_t size)
-{
- DWORD ret;
- ret = GetCurrentDirectoryA(size, str);
- str[size - 1] = 0;
- return ret == 0 ? false : true;
-}
-
-void
-DebugMessage(const char *format, ...)
-{
- char buf[4096];
-
- va_list ap;
- va_start(ap, format);
- fflush(stdout);
- vsnprintf(buf, sizeof buf, format, ap);
- va_end(ap);
-
- OutputDebugStringA(buf);
-
- /*
- * Also write the message to stderr, when a debugger is not present (to
- * avoid duplicate messages in command line debuggers).
- */
-#if _WIN32_WINNT > 0x0400
- if (!IsDebuggerPresent()) {
- fflush(stdout);
- fputs(buf, stderr);
- fflush(stderr);
- }
-#endif
-}
-
-long long GetTime(void)
-{
- static LARGE_INTEGER frequency;
- LARGE_INTEGER counter;
- if (!frequency.QuadPart)
- QueryPerformanceFrequency(&frequency);
- QueryPerformanceCounter(&counter);
- return counter.QuadPart*1000000LL/frequency.QuadPart;
-}
-
-void
-Abort(void)
-{
-#ifndef NDEBUG
- DebugBreak();
-#else
- ExitProcess(0);
-#endif
-}
-
-
-static LPTOP_LEVEL_EXCEPTION_FILTER prevExceptionFilter = NULL;
-static void (*gCallback)(void) = NULL;
-
-static LONG WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
-{
- if (gCallback) {
- gCallback();
- }
-
- if (prevExceptionFilter) {
- return prevExceptionFilter(pExceptionInfo);
- } else {
- return EXCEPTION_CONTINUE_SEARCH;
- }
-}
-
-void
-SetExceptionCallback(void (*callback)(void))
-{
- assert(!gCallback);
-
- if (!gCallback) {
- gCallback = callback;
-
- assert(!prevExceptionFilter);
- prevExceptionFilter = SetUnhandledExceptionFilter(UnhandledExceptionFilter);
- }
-}
-
-void
-ResetExceptionCallback(void)
-{
- gCallback = NULL;
-}
-
-
-} /* namespace OS */
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2011 Zack Rusin
- * 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.
- *
- **************************************************************************/
-
-
-#include "trace_file.hpp"
-
-#include "trace_snappyfile.hpp"
-
-#include <assert.h>
-#include <string.h>
-
-#include <zlib.h>
-
-#include "os.hpp"
-
-#include <iostream>
-
-using namespace Trace;
-
-
-File::File(const std::string &filename,
- File::Mode mode)
- : m_mode(mode),
- m_isOpened(false)
-{
- if (!filename.empty()) {
- open(filename, m_mode);
- }
-}
-
-File::~File()
-{
- close();
-}
-
-
-void File::setCurrentOffset(const File::Offset &offset)
-{
- assert(0);
-}
-
-bool File::isZLibCompressed(const std::string &filename)
-{
- std::fstream stream(filename.c_str(),
- std::fstream::binary | std::fstream::in);
- if (!stream.is_open())
- return false;
-
- unsigned char byte1, byte2;
- stream >> byte1;
- stream >> byte2;
- stream.close();
-
- return (byte1 == 0x1f && byte2 == 0x8b);
-}
-
-
-bool File::isSnappyCompressed(const std::string &filename)
-{
- std::fstream stream(filename.c_str(),
- std::fstream::binary | std::fstream::in);
- if (!stream.is_open())
- return false;
-
- unsigned char byte1, byte2;
- stream >> byte1;
- stream >> byte2;
- stream.close();
-
- return (byte1 == SNAPPY_BYTE1 && byte2 == SNAPPY_BYTE2);
-}
-
-typedef struct gz_stream {
- z_stream stream;
- int z_err; /* error code for last stream operation */
- int z_eof; /* set if end of input file */
- FILE *file; /* .gz file */
-} gz_dummy_stream;
-
-ZLibFile::ZLibFile(const std::string &filename,
- File::Mode mode)
- : File(filename, mode),
- m_gzFile(NULL)
-{
-}
-
-ZLibFile::~ZLibFile()
-{
-}
-
-bool ZLibFile::rawOpen(const std::string &filename, File::Mode mode)
-{
- m_gzFile = gzopen(filename.c_str(),
- (mode == File::Write) ? "wb" : "rb");
-
- if (mode == File::Read && m_gzFile) {
- //XXX: unfortunately zlib doesn't support
- // SEEK_END or we could've done:
- //m_endOffset = gzseek(m_gzFile, 0, SEEK_END);
- //gzrewind(m_gzFile);
- gz_dummy_stream *stream = (gz_dummy_stream *)m_gzFile;
- long loc = ftell(stream->file);
- fseek(stream->file,0,SEEK_END);
- m_endOffset = ftell(stream->file);
- fseek(stream->file, loc, SEEK_SET);
- }
-
- return m_gzFile != NULL;
-}
-
-bool ZLibFile::rawWrite(const void *buffer, size_t length)
-{
- return gzwrite(m_gzFile, buffer, length) != -1;
-}
-
-bool ZLibFile::rawRead(void *buffer, size_t length)
-{
- return gzread(m_gzFile, buffer, length) != -1;
-}
-
-int ZLibFile::rawGetc()
-{
- return gzgetc(m_gzFile);
-}
-
-void ZLibFile::rawClose()
-{
- if (m_gzFile) {
- gzclose(m_gzFile);
- m_gzFile = NULL;
- }
-}
-
-void ZLibFile::rawFlush()
-{
- gzflush(m_gzFile, Z_SYNC_FLUSH);
-}
-
-File::Offset ZLibFile::currentOffset()
-{
- return File::Offset(gztell(m_gzFile));
-}
-
-bool ZLibFile::supportsOffsets() const
-{
- return false;
-}
-
-bool ZLibFile::rawSkip(size_t)
-{
- return false;
-}
-
-int ZLibFile::rawPercentRead()
-{
- gz_dummy_stream *stream = (gz_dummy_stream *)m_gzFile;
- return 100 * (ftell(stream->file) / m_endOffset);
-}
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2011 Zack Rusin
- * 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.
- *
- **************************************************************************/
-
-
-#ifndef TRACE_FILE_HPP
-#define TRACE_FILE_HPP
-
-#include <string>
-#include <fstream>
-#include <stdint.h>
-
-namespace Trace {
-
-class File {
-public:
- enum Mode {
- Read,
- Write
- };
- struct Offset {
- Offset(uint64_t _chunk = 0, uint32_t _offsetInChunk = 0)
- : chunk(_chunk),
- offsetInChunk(_offsetInChunk)
- {}
- uint64_t chunk;
- uint32_t offsetInChunk;
- };
-
-public:
- static bool isZLibCompressed(const std::string &filename);
- static bool isSnappyCompressed(const std::string &filename);
-public:
- File(const std::string &filename = std::string(),
- File::Mode mode = File::Read);
- virtual ~File();
-
- bool isOpened() const;
- File::Mode mode() const;
-
- bool open(const std::string &filename, File::Mode mode);
- bool write(const void *buffer, size_t length);
- bool read(void *buffer, size_t length);
- void close();
- void flush(void);
- int getc();
- bool skip(size_t length);
- int percentRead();
-
- virtual bool supportsOffsets() const = 0;
- virtual File::Offset currentOffset() = 0;
- virtual void setCurrentOffset(const File::Offset &offset);
-protected:
- virtual bool rawOpen(const std::string &filename, File::Mode mode) = 0;
- virtual bool rawWrite(const void *buffer, size_t length) = 0;
- virtual bool rawRead(void *buffer, size_t length) = 0;
- virtual int rawGetc() = 0;
- virtual void rawClose() = 0;
- virtual void rawFlush() = 0;
- virtual bool rawSkip(size_t length) = 0;
- virtual int rawPercentRead() = 0;
-
-protected:
- File::Mode m_mode;
- bool m_isOpened;
-};
-
-inline bool File::isOpened() const
-{
- return m_isOpened;
-}
-
-inline File::Mode File::mode() const
-{
- return m_mode;
-}
-
-inline bool File::open(const std::string &filename, File::Mode mode)
-{
- if (m_isOpened) {
- close();
- }
- m_isOpened = rawOpen(filename, mode);
- m_mode = mode;
-
- return m_isOpened;
-}
-
-inline bool File::write(const void *buffer, size_t length)
-{
- if (!m_isOpened || m_mode != File::Write) {
- return false;
- }
- return rawWrite(buffer, length);
-}
-
-inline bool File::read(void *buffer, size_t length)
-{
- if (!m_isOpened || m_mode != File::Read) {
- return false;
- }
- return rawRead(buffer, length);
-}
-
-inline int File::percentRead()
-{
- if (!m_isOpened || m_mode != File::Read) {
- return 0;
- }
- return rawPercentRead();
-}
-
-inline void File::close()
-{
- if (m_isOpened) {
- rawClose();
- m_isOpened = false;
- }
-}
-
-inline void File::flush(void)
-{
- if (m_mode == File::Write) {
- rawFlush();
- }
-}
-
-inline int File::getc()
-{
- if (!m_isOpened || m_mode != File::Read) {
- return -1;
- }
- return rawGetc();
-}
-
-inline bool File::skip(size_t length)
-{
- if (!m_isOpened || m_mode != File::Read) {
- return false;
- }
- return rawSkip(length);
-}
-
-class ZLibFile : public File {
-public:
- ZLibFile(const std::string &filename = std::string(),
- File::Mode mode = File::Read);
- virtual ~ZLibFile();
-
-
- virtual bool supportsOffsets() const;
- virtual File::Offset currentOffset();
-protected:
- virtual bool rawOpen(const std::string &filename, File::Mode mode);
- virtual bool rawWrite(const void *buffer, size_t length);
- virtual bool rawRead(void *buffer, size_t length);
- virtual int rawGetc();
- virtual void rawClose();
- virtual void rawFlush();
- virtual bool rawSkip(size_t length);
- virtual int rawPercentRead();
-private:
- void *m_gzFile;
- double m_endOffset;
-};
-
-inline bool
-operator<(const File::Offset &one, const File::Offset &two)
-{
- return one.chunk < two.chunk ||
- (one.chunk == two.chunk && one.offsetInChunk < two.offsetInChunk);
-}
-
-inline bool
-operator==(const File::Offset &one, const File::Offset &two)
-{
- return one.chunk == two.chunk &&
- one.offsetInChunk == two.offsetInChunk;
-}
-
-inline bool
-operator>=(const File::Offset &one, const File::Offset &two)
-{
- return one.chunk > two.chunk ||
- (one.chunk == two.chunk && one.offsetInChunk >= two.offsetInChunk);
-}
-
-inline bool
-operator>(const File::Offset &one, const File::Offset &two)
-{
- return two < one;
-}
-
-inline bool
-operator<=(const File::Offset &one, const File::Offset &two)
-{
- return two >= one;
-}
-
-
-}
-
-#endif
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-/*
- * Trace binary format.
- *
- * Grammar:
- *
- * trace = event* EOF
- *
- * event = EVENT_ENTER call_sig call_detail+
- * | EVENT_LEAVE call_no call_detail+
- *
- * call_sig = sig_id ( name arg_names )?
- *
- * call_detail = ARG index value
- * | RET value
- * | END
- *
- * value = NULL
- * | FALSE
- * | TRUE
- * | SINT int
- * | UINT int
- * | FLOAT float
- * | DOUBLE double
- * | STRING string
- * | BLOB string
- * | ENUM enum_sig
- * | BITMASK bitmask_sig value
- * | ARRAY length value+
- * | STRUCT struct_sig value+
- * | OPAQUE int
- *
- * call_sig = id name arg_name*
- * | id
- *
- * enum_sig = id name value
- * | id
- *
- * bitmask_sig = id count (name value)+
- * | id
- *
- * string = length (BYTE)*
- *
- */
-
-#ifndef _TRACE_FORMAT_HPP_
-#define _TRACE_FORMAT_HPP_
-
-namespace Trace {
-
-#define TRACE_VERSION 1
-
-enum Event {
- EVENT_ENTER = 0,
- EVENT_LEAVE,
-};
-
-enum CallDetail {
- CALL_END = 0,
- CALL_ARG,
- CALL_RET,
- CALL_THREAD,
-};
-
-enum Type {
- TYPE_NULL = 0,
- TYPE_FALSE,
- TYPE_TRUE,
- TYPE_SINT,
- TYPE_UINT,
- TYPE_FLOAT,
- TYPE_DOUBLE,
- TYPE_STRING, // Null terminated, human readible string
- TYPE_BLOB, // Block of bytes
- TYPE_ENUM,
- TYPE_BITMASK,
- TYPE_ARRAY,
- TYPE_STRUCT,
- TYPE_OPAQUE,
-};
-
-
-} /* namespace Trace */
-
-#endif /* _TRACE_FORMAT_HPP_ */
+++ /dev/null
-#include "trace_loader.hpp"
-
-
-using namespace Trace;
-
-Loader::Loader()
- : m_frameMarker(FrameMarker_SwapBuffers)
-{
-}
-
-Loader::~Loader()
-{
- close();
-}
-
-Loader::FrameMarker Loader::frameMarker() const
-{
- return m_frameMarker;
-}
-
-void Loader::setFrameMarker(Loader::FrameMarker marker)
-{
- m_frameMarker = marker;
-}
-
-int Loader::numberOfFrames() const
-{
- return m_frameBookmarks.size();
-}
-
-int Loader::numberOfCallsInFrame(int frameIdx) const
-{
- if (frameIdx > m_frameBookmarks.size()) {
- return 0;
- }
- FrameBookmarks::const_iterator itr =
- m_frameBookmarks.find(frameIdx);
- return itr->second.numberOfCalls;
-}
-
-bool Loader::open(const char *filename)
-{
- if (!m_parser.open(filename)) {
- std::cerr << "error: failed to open " << filename << "\n";
- return false;
- }
- if (!m_parser.supportsOffsets()) {
- std::cerr << "error: " <<filename<< " doesn't support seeking "
- << "\n";
- return false;
- }
-
- Trace::Call *call;
- ParseBookmark startBookmark;
- int numOfFrames = 0;
- int numOfCalls = 0;
- int lastPercentReport = 0;
-
- m_parser.getBookmark(startBookmark);
-
- while ((call = m_parser.scan_call())) {
- ++numOfCalls;
-
- if (isCallAFrameMarker(call)) {
- FrameBookmark frameBookmark(startBookmark);
- frameBookmark.numberOfCalls = numOfCalls;
-
- m_frameBookmarks[numOfFrames] = frameBookmark;
- ++numOfFrames;
-
- if (m_parser.percentRead() - lastPercentReport >= 5) {
- std::cerr << "\tPercent scanned = "
- << m_parser.percentRead()
- << "..."<<std::endl;
- lastPercentReport = m_parser.percentRead();
- }
-
- m_parser.getBookmark(startBookmark);
- numOfCalls = 0;
- }
- //call->dump(std::cout, color);
- delete call;
- }
- return true;
-}
-
-void Loader::close()
-{
- m_parser.close();
-}
-
-bool Loader::isCallAFrameMarker(const Trace::Call *call) const
-{
- std::string name = call->name();
-
- switch (m_frameMarker) {
- case FrameMarker_SwapBuffers:
- return name.find("SwapBuffers") != std::string::npos ||
- name == "CGLFlushDrawable" ||
- name == "glFrameTerminatorGREMEDY";
- break;
- case FrameMarker_Flush:
- return name == "glFlush";
- break;
- case FrameMarker_Finish:
- return name == "glFinish";
- break;
- case FrameMarker_Clear:
- return name == "glClear";
- break;
- }
- return false;
-}
-
-std::vector<Trace::Call *> Loader::frame(int idx)
-{
- int numOfCalls = numberOfCallsInFrame(idx);
- if (numOfCalls) {
- const FrameBookmark &frameBookmark = m_frameBookmarks[idx];
- std::vector<Trace::Call*> calls(numOfCalls);
- m_parser.setBookmark(frameBookmark.start);
-
- Trace::Call *call;
- int parsedCalls = 0;
- while ((call = m_parser.parse_call())) {
-
- calls[parsedCalls] = call;
- ++parsedCalls;
-
- if (isCallAFrameMarker(call)) {
- break;
- }
-
- }
- assert(parsedCalls == numOfCalls);
- return calls;
- }
- return std::vector<Trace::Call*>();
-}
+++ /dev/null
-#ifndef TRACE_LOADER_HPP
-#define TRACE_LOADER_HPP
-
-#include "trace_file.hpp"
-#include "trace_parser.hpp"
-
-#include <string>
-#include <map>
-#include <queue>
-#include <vector>
-
-namespace Trace {
-
-class Frame;
-
-class Loader
-{
-public:
- enum FrameMarker {
- FrameMarker_SwapBuffers,
- FrameMarker_Flush,
- FrameMarker_Finish,
- FrameMarker_Clear
- };
-public:
- Loader();
- ~Loader();
-
- Loader::FrameMarker frameMarker() const;
- void setFrameMarker(Loader::FrameMarker marker);
-
- int numberOfFrames() const;
- int numberOfCallsInFrame(int frameIdx) const;
-
- bool open(const char *filename);
- void close();
-
- std::vector<Trace::Call*> frame(int idx);
-
-private:
- struct FrameBookmark {
- FrameBookmark()
- : numberOfCalls(0)
- {}
- FrameBookmark(const ParseBookmark &s)
- : start(s),
- numberOfCalls(0)
- {}
-
- ParseBookmark start;
- int numberOfCalls;
- };
- bool isCallAFrameMarker(const Trace::Call *call) const;
-
-private:
- Trace::Parser m_parser;
- FrameMarker m_frameMarker;
-
- typedef std::map<int, FrameBookmark> FrameBookmarks;
- FrameBookmarks m_frameBookmarks;
-};
-
-}
-
-#endif // TRACE_LOADER_HPP
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2007-2011 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-
-#include <assert.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "os.hpp"
-#include "trace_file.hpp"
-#include "trace_writer.hpp"
-#include "trace_format.hpp"
-
-
-namespace Trace {
-
-
-static void exceptionCallback(void)
-{
- OS::DebugMessage("apitrace: flushing trace due to an exception\n");
- localWriter.flush();
-}
-
-
-LocalWriter::LocalWriter() :
- acquired(0)
-{}
-
-LocalWriter::~LocalWriter()
-{
- OS::ResetExceptionCallback();
-}
-
-void
-LocalWriter::open(void) {
-
- static unsigned dwCounter = 0;
-
- const char *szExtension = "trace";
- char szFileName[PATH_MAX];
- const char *lpFileName;
-
- lpFileName = getenv("TRACE_FILE");
- if (lpFileName) {
- strncpy(szFileName, lpFileName, PATH_MAX);
- }
- else {
- char szProcessName[PATH_MAX];
- char szCurrentDir[PATH_MAX];
- OS::GetProcessName(szProcessName, PATH_MAX);
- OS::GetCurrentDir(szCurrentDir, PATH_MAX);
-
- for (;;) {
- FILE *file;
-
- if (dwCounter)
- snprintf(szFileName, PATH_MAX, "%s%c%s.%u.%s", szCurrentDir, PATH_SEP, szProcessName, dwCounter, szExtension);
- else
- snprintf(szFileName, PATH_MAX, "%s%c%s.%s", szCurrentDir, PATH_SEP, szProcessName, szExtension);
-
- file = fopen(szFileName, "rb");
- if (file == NULL)
- break;
-
- fclose(file);
-
- ++dwCounter;
- }
- }
-
- OS::DebugMessage("apitrace: tracing to %s\n", szFileName);
-
- Writer::open(szFileName);
-
- OS::SetExceptionCallback(exceptionCallback);
-
-#if 0
- // For debugging the exception handler
- *((int *)0) = 0;
-#endif
-}
-
-unsigned LocalWriter::beginEnter(const FunctionSig *sig) {
- OS::AcquireMutex();
- ++acquired;
-
- if (!m_file->isOpened()) {
- open();
- }
-
- return Writer::beginEnter(sig);
-}
-
-void LocalWriter::endEnter(void) {
- Writer::endEnter();
- --acquired;
- OS::ReleaseMutex();
-}
-
-void LocalWriter::beginLeave(unsigned call) {
- OS::AcquireMutex();
- ++acquired;
- Writer::beginLeave(call);
-}
-
-void LocalWriter::endLeave(void) {
- Writer::endLeave();
- --acquired;
- OS::ReleaseMutex();
-}
-
-void LocalWriter::flush(void) {
- /*
- * Do nothing if the mutex is already acquired (e.g., if a segfault happen
- * while writing the file) to prevent dead-lock.
- */
-
- if (!acquired) {
- OS::AcquireMutex();
- if (m_file->isOpened()) {
- m_file->flush();
- }
- OS::ReleaseMutex();
- }
-}
-
-
-LocalWriter localWriter;
-
-
-} /* namespace Trace */
-
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-
-#include "formatter.hpp"
-#include "trace_model.hpp"
-
-
-namespace Trace {
-
-
-Call::~Call() {
- for (unsigned i = 0; i < args.size(); ++i) {
- delete args[i];
- }
-
- if (ret) {
- delete ret;
- }
-}
-
-
-String::~String() {
- delete [] value;
-}
-
-
-Struct::~Struct() {
- for (std::vector<Value *>::iterator it = members.begin(); it != members.end(); ++it) {
- delete *it;
- }
-}
-
-
-Array::~Array() {
- for (std::vector<Value *>::iterator it = values.begin(); it != values.end(); ++it) {
- delete *it;
- }
-}
-
-Blob::~Blob() {
- // Blobs are often bound and referred during many calls, so we can't delete
- // them here in that case.
- //
- // Once bound there is no way to know when they were unbound, which
- // effectively means we have to leak them. A better solution would be to
- // keep a list of bound pointers, and defer the destruction to when the
- // trace in question has been fully processed.
- if (!bound) {
- delete [] buf;
- }
-}
-
-
-// bool cast
-bool Null ::toBool(void) const { return false; }
-bool Bool ::toBool(void) const { return value; }
-bool SInt ::toBool(void) const { return value != 0; }
-bool UInt ::toBool(void) const { return value != 0; }
-bool Float ::toBool(void) const { return value != 0; }
-bool String ::toBool(void) const { return true; }
-bool Enum ::toBool(void) const { return sig->value != 0; }
-bool Struct ::toBool(void) const { return true; }
-bool Array ::toBool(void) const { return true; }
-bool Blob ::toBool(void) const { return true; }
-bool Pointer::toBool(void) const { return value != 0; }
-
-
-// signed integer cast
-signed long long Value ::toSInt(void) const { assert(0); return 0; }
-signed long long Null ::toSInt(void) const { return 0; }
-signed long long Bool ::toSInt(void) const { return static_cast<signed long long>(value); }
-signed long long SInt ::toSInt(void) const { return value; }
-signed long long UInt ::toSInt(void) const { assert(static_cast<signed long long>(value) >= 0); return static_cast<signed long long>(value); }
-signed long long Float ::toSInt(void) const { return static_cast<signed long long>(value); }
-signed long long Enum ::toSInt(void) const { return sig->value; }
-
-
-// unsigned integer cast
-unsigned long long Value ::toUInt(void) const { assert(0); return 0; }
-unsigned long long Null ::toUInt(void) const { return 0; }
-unsigned long long Bool ::toUInt(void) const { return static_cast<unsigned long long>(value); }
-unsigned long long SInt ::toUInt(void) const { assert(value >= 0); return static_cast<signed long long>(value); }
-unsigned long long UInt ::toUInt(void) const { return value; }
-unsigned long long Float ::toUInt(void) const { return static_cast<unsigned long long>(value); }
-unsigned long long Enum ::toUInt(void) const { assert(sig->value >= 0); return sig->value; }
-
-
-// floating point cast
-float Value ::toFloat(void) const { assert(0); return 0; }
-float Null ::toFloat(void) const { return 0; }
-float Bool ::toFloat(void) const { return static_cast<float>(value); }
-float SInt ::toFloat(void) const { return static_cast<float>(value); }
-float UInt ::toFloat(void) const { return static_cast<float>(value); }
-float Float ::toFloat(void) const { return value; }
-float Enum ::toFloat(void) const { return static_cast<float>(sig->value); }
-
-
-// floating point cast
-double Value ::toDouble(void) const { assert(0); return 0; }
-double Null ::toDouble(void) const { return 0; }
-double Bool ::toDouble(void) const { return static_cast<double>(value); }
-double SInt ::toDouble(void) const { return static_cast<double>(value); }
-double UInt ::toDouble(void) const { return static_cast<double>(value); }
-double Float ::toDouble(void) const { return value; }
-double Enum ::toDouble(void) const { return static_cast<double>(sig->value); }
-
-
-// pointer cast
-void * Value ::toPointer(void) const { assert(0); return NULL; }
-void * Null ::toPointer(void) const { return NULL; }
-void * Blob ::toPointer(void) const { return buf; }
-void * Pointer::toPointer(void) const { return (void *)value; }
-
-void * Value ::toPointer(bool bind) { assert(0); return NULL; }
-void * Null ::toPointer(bool bind) { return NULL; }
-void * Blob ::toPointer(bool bind) { if (bind) bound = true; return buf; }
-void * Pointer::toPointer(bool bind) { return (void *)value; }
-
-
-// pointer cast
-unsigned long long Value ::toUIntPtr(void) const { assert(0); return 0; }
-unsigned long long Null ::toUIntPtr(void) const { return 0; }
-unsigned long long Pointer::toUIntPtr(void) const { return value; }
-
-
-// string cast
-const char * Value ::toString(void) const { assert(0); return NULL; }
-const char * Null ::toString(void) const { return NULL; }
-const char * String::toString(void) const { return value; }
-
-
-// virtual Value::visit()
-void Null ::visit(Visitor &visitor) { visitor.visit(this); }
-void Bool ::visit(Visitor &visitor) { visitor.visit(this); }
-void SInt ::visit(Visitor &visitor) { visitor.visit(this); }
-void UInt ::visit(Visitor &visitor) { visitor.visit(this); }
-void Float ::visit(Visitor &visitor) { visitor.visit(this); }
-void String ::visit(Visitor &visitor) { visitor.visit(this); }
-void Enum ::visit(Visitor &visitor) { visitor.visit(this); }
-void Bitmask::visit(Visitor &visitor) { visitor.visit(this); }
-void Struct ::visit(Visitor &visitor) { visitor.visit(this); }
-void Array ::visit(Visitor &visitor) { visitor.visit(this); }
-void Blob ::visit(Visitor &visitor) { visitor.visit(this); }
-void Pointer::visit(Visitor &visitor) { visitor.visit(this); }
-
-
-void Visitor::visit(Null *) { assert(0); }
-void Visitor::visit(Bool *) { assert(0); }
-void Visitor::visit(SInt *) { assert(0); }
-void Visitor::visit(UInt *) { assert(0); }
-void Visitor::visit(Float *) { assert(0); }
-void Visitor::visit(String *) { assert(0); }
-void Visitor::visit(Enum *node) { assert(0); }
-void Visitor::visit(Bitmask *node) { visit(static_cast<UInt *>(node)); }
-void Visitor::visit(Struct *) { assert(0); }
-void Visitor::visit(Array *) { assert(0); }
-void Visitor::visit(Blob *) { assert(0); }
-void Visitor::visit(Pointer *) { assert(0); }
-
-
-class Dumper : public Visitor
-{
-protected:
- std::ostream &os;
- Formatter::Formatter *formatter;
- Formatter::Attribute *normal;
- Formatter::Attribute *bold;
- Formatter::Attribute *italic;
- Formatter::Attribute *red;
- Formatter::Attribute *pointer;
- Formatter::Attribute *literal;
-
-public:
- Dumper(std::ostream &_os, bool color) : os(_os) {
- formatter = Formatter::defaultFormatter(color);
- normal = formatter->normal();
- bold = formatter->bold();
- italic = formatter->italic();
- red = formatter->color(Formatter::RED);
- pointer = formatter->color(Formatter::GREEN);
- literal = formatter->color(Formatter::BLUE);
- }
-
- ~Dumper() {
- delete normal;
- delete bold;
- delete italic;
- delete red;
- delete pointer;
- delete literal;
- delete formatter;
- }
-
- void visit(Null *) {
- os << "NULL";
- }
-
- void visit(Bool *node) {
- os << literal << (node->value ? "true" : "false") << normal;
- }
-
- void visit(SInt *node) {
- os << literal << node->value << normal;
- }
-
- void visit(UInt *node) {
- os << literal << node->value << normal;
- }
-
- void visit(Float *node) {
- os << literal << node->value << normal;
- }
-
- void visit(String *node) {
- os << literal << "\"";
- for (const char *it = node->value; *it; ++it) {
- unsigned char c = (unsigned char) *it;
- if (c == '\"')
- os << "\\\"";
- else if (c == '\\')
- os << "\\\\";
- else if (c >= 0x20 && c <= 0x7e)
- os << c;
- else if (c == '\t') {
- os << "\t";
- } else if (c == '\r') {
- // Ignore carriage-return
- } else if (c == '\n') {
- // Reset formatting so that it looks correct with 'less -R'
- os << normal << '\n' << literal;
- } else {
- unsigned octal0 = c & 0x7;
- unsigned octal1 = (c >> 3) & 0x7;
- unsigned octal2 = (c >> 3) & 0x7;
- os << "\\";
- if (octal2)
- os << octal2;
- if (octal1)
- os << octal1;
- os << octal0;
- }
- }
- os << "\"" << normal;
- }
-
- void visit(Enum *node) {
- os << literal << node->sig->name << normal;
- }
-
- void visit(Bitmask *bitmask) {
- unsigned long long value = bitmask->value;
- const BitmaskSig *sig = bitmask->sig;
- bool first = true;
- for (const BitmaskFlag *it = sig->flags; value != 0 && it != sig->flags + sig->num_flags; ++it) {
- if ((it->value && (value & it->value) == it->value) ||
- (!it->value && value == 0)) {
- if (!first) {
- os << " | ";
- }
- os << literal << it->name << normal;
- value &= ~it->value;
- first = false;
- }
- }
- if (value || first) {
- if (!first) {
- os << " | ";
- }
- os << literal << "0x" << std::hex << value << std::dec << normal;
- }
- }
-
- void visit(Struct *s) {
- const char *sep = "";
- os << "{";
- for (unsigned i = 0; i < s->members.size(); ++i) {
- os << sep << italic << s->sig->member_names[i] << normal << " = ";
- _visit(s->members[i]);
- sep = ", ";
- }
- os << "}";
- }
-
- void visit(Array *array) {
- if (array->values.size() == 1) {
- os << "&";
- _visit(array->values[0]);
- }
- else {
- const char *sep = "";
- os << "{";
- for (std::vector<Value *>::iterator it = array->values.begin(); it != array->values.end(); ++it) {
- os << sep;
- _visit(*it);
- sep = ", ";
- }
- os << "}";
- }
- }
-
- void visit(Blob *blob) {
- os << pointer << "blob(" << blob->size << ")" << normal;
- }
-
- void visit(Pointer *p) {
- os << pointer << "0x" << std::hex << p->value << std::dec << normal;
- }
-
- void visit(Call *call) {
- const char *sep = "";
- os << bold << call->sig->name << normal << "(";
- for (unsigned i = 0; i < call->args.size(); ++i) {
- os << sep << italic << call->sig->arg_names[i] << normal << " = ";
- if (call->args[i]) {
- _visit(call->args[i]);
- } else {
- os << "?";
- }
- sep = ", ";
- }
- os << ")";
- if (call->ret) {
- os << " = ";
- _visit(call->ret);
- }
- os << "\n";
- }
-};
-
-
-void Value::dump(std::ostream &os, bool color) {
- Dumper d(os, color);
- visit(d);
-}
-
-
-static Null null;
-
-const Value & Value::operator[](size_t index) const {
- const Array *array = dynamic_cast<const Array *>(this);
- if (array) {
- if (index < array->values.size()) {
- return *array->values[index];
- }
- }
- return null;
-}
-
-void Call::dump(std::ostream &os, bool color) {
- Dumper d(os, color);
- os << no << " ";
- d.visit(this);
-}
-
-
-} /* namespace Trace */
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-/*
- * Object hierarchy for describing the traces in memory.
- */
-
-#ifndef _TRACE_MODEL_HPP_
-#define _TRACE_MODEL_HPP_
-
-
-#include <assert.h>
-
-#include <map>
-#include <vector>
-#include <iostream>
-
-
-namespace Trace {
-
-
-typedef unsigned Id;
-
-
-struct FunctionSig {
- Id id;
- const char *name;
- unsigned num_args;
- const char **arg_names;
-};
-
-
-struct StructSig {
- Id id;
- const char *name;
- unsigned num_members;
- const char **member_names;
-};
-
-
-struct EnumSig {
- Id id;
- const char *name;
- signed long long value;
-};
-
-
-struct BitmaskFlag {
- const char *name;
- unsigned long long value;
-};
-
-
-struct BitmaskSig {
- Id id;
- unsigned num_flags;
- const BitmaskFlag *flags;
-};
-
-
-class Visitor;
-
-
-class Value
-{
-public:
- virtual ~Value() {}
- virtual void visit(Visitor &visitor) = 0;
-
- virtual bool toBool(void) const = 0;
- virtual signed long long toSInt(void) const;
- virtual unsigned long long toUInt(void) const;
- virtual float toFloat(void) const;
- virtual double toDouble(void) const;
-
- virtual void *toPointer(void) const;
- virtual void *toPointer(bool bind);
- virtual unsigned long long toUIntPtr(void) const;
- virtual const char *toString(void) const;
-
- const Value & operator[](size_t index) const;
-
- void dump(std::ostream &os, bool color=true);
-};
-
-
-class Null : public Value
-{
-public:
- bool toBool(void) const;
- signed long long toSInt(void) const;
- unsigned long long toUInt(void) const;
- virtual float toFloat(void) const;
- virtual double toDouble(void) const;
- void *toPointer(void) const;
- void *toPointer(bool bind);
- unsigned long long toUIntPtr(void) const;
- const char *toString(void) const;
- void visit(Visitor &visitor);
-};
-
-
-class Bool : public Value
-{
-public:
- Bool(bool _value) : value(_value) {}
-
- bool toBool(void) const;
- signed long long toSInt(void) const;
- unsigned long long toUInt(void) const;
- virtual float toFloat(void) const;
- virtual double toDouble(void) const;
- void visit(Visitor &visitor);
-
- bool value;
-};
-
-
-class SInt : public Value
-{
-public:
- SInt(signed long long _value) : value(_value) {}
-
- bool toBool(void) const;
- signed long long toSInt(void) const;
- unsigned long long toUInt(void) const;
- virtual float toFloat(void) const;
- virtual double toDouble(void) const;
- void visit(Visitor &visitor);
-
- signed long long value;
-};
-
-
-class UInt : public Value
-{
-public:
- UInt(unsigned long long _value) : value(_value) {}
-
- bool toBool(void) const;
- signed long long toSInt(void) const;
- unsigned long long toUInt(void) const;
- virtual float toFloat(void) const;
- virtual double toDouble(void) const;
- void visit(Visitor &visitor);
-
- unsigned long long value;
-};
-
-
-class Float : public Value
-{
-public:
- Float(double _value) : value(_value) {}
-
- bool toBool(void) const;
- signed long long toSInt(void) const;
- unsigned long long toUInt(void) const;
- virtual float toFloat(void) const;
- virtual double toDouble(void) const;
- void visit(Visitor &visitor);
-
- double value;
-};
-
-
-class String : public Value
-{
-public:
- String(const char * _value) : value(_value) {}
- ~String();
-
- bool toBool(void) const;
- const char *toString(void) const;
- void visit(Visitor &visitor);
-
- const char * value;
-};
-
-
-class Enum : public Value
-{
-public:
- Enum(const EnumSig *_sig) : sig(_sig) {}
-
- bool toBool(void) const;
- signed long long toSInt(void) const;
- unsigned long long toUInt(void) const;
- virtual float toFloat(void) const;
- virtual double toDouble(void) const;
- void visit(Visitor &visitor);
-
- const EnumSig *sig;
-};
-
-
-class Bitmask : public UInt
-{
-public:
- Bitmask(const BitmaskSig *_sig, unsigned long long _value) : UInt(_value), sig(_sig) {}
-
- void visit(Visitor &visitor);
-
- const BitmaskSig *sig;
-};
-
-
-class Struct : public Value
-{
-public:
- Struct(StructSig *_sig) : sig(_sig), members(_sig->num_members) { }
- ~Struct();
-
- bool toBool(void) const;
- void visit(Visitor &visitor);
-
- const StructSig *sig;
- std::vector<Value *> members;
-};
-
-
-class Array : public Value
-{
-public:
- Array(size_t len) : values(len) {}
- ~Array();
-
- bool toBool(void) const;
- void visit(Visitor &visitor);
-
- std::vector<Value *> values;
-};
-
-
-class Blob : public Value
-{
-public:
- Blob(size_t _size) {
- size = _size;
- buf = new char[_size];
- bound = false;
- }
-
- ~Blob();
-
- bool toBool(void) const;
- void *toPointer(void) const;
- void *toPointer(bool bind);
- void visit(Visitor &visitor);
-
- size_t size;
- char *buf;
- bool bound;
-};
-
-
-class Pointer : public UInt
-{
-public:
- Pointer(unsigned long long value) : UInt(value) {}
-
- bool toBool(void) const;
- void *toPointer(void) const;
- void *toPointer(bool bind);
- unsigned long long toUIntPtr(void) const;
- void visit(Visitor &visitor);
-};
-
-
-class Visitor
-{
-public:
- virtual void visit(Null *);
- virtual void visit(Bool *);
- virtual void visit(SInt *);
- virtual void visit(UInt *);
- virtual void visit(Float *);
- virtual void visit(String *);
- virtual void visit(Enum *);
- virtual void visit(Bitmask *);
- virtual void visit(Struct *);
- virtual void visit(Array *);
- virtual void visit(Blob *);
- virtual void visit(Pointer *);
-
-protected:
- inline void _visit(Value *value) {
- if (value) {
- value->visit(*this);
- }
- }
-};
-
-
-inline std::ostream & operator <<(std::ostream &os, Value *value) {
- if (value) {
- value->dump(os);
- }
- return os;
-}
-
-
-class Call
-{
-public:
- unsigned no;
- const FunctionSig *sig;
- std::vector<Value *> args;
- Value *ret;
-
- Call(FunctionSig *_sig) : sig(_sig), args(_sig->num_args), ret(0) { }
- ~Call();
-
- inline const char * name(void) const {
- return sig->name;
- }
-
- inline Value & arg(unsigned index) {
- assert(index < args.size());
- return *(args[index]);
- }
-
- void dump(std::ostream &os, bool color=true);
-};
-
-
-inline std::ostream & operator <<(std::ostream &os, Call &call) {
- call.dump(os);
- return os;
-}
-
-
-} /* namespace Trace */
-
-#endif /* _TRACE_MODEL_HPP_ */
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * 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.
- *
- **************************************************************************/
-
-
-#include "trace_writer.hpp"
-
-
-namespace Trace {
-
-
-class ModelWriter : public Visitor
-{
-protected:
- Writer &writer;
-
-public:
- ModelWriter(Writer &_writer) :
- writer(_writer) {
- }
-
- void visit(Null *) {
- writer.writeNull();
- }
-
- void visit(Bool *node) {
- writer.writeBool(node->value);
- }
-
- void visit(SInt *node) {
- writer.writeSInt(node->value);
- }
-
- void visit(UInt *node) {
- writer.writeUInt(node->value);
- }
-
- void visit(Float *node) {
- writer.writeFloat(node->value);
- }
-
- void visit(String *node) {
- writer.writeString(node->value);
- }
-
- void visit(Enum *node) {
- writer.writeEnum(node->sig);
- }
-
- void visit(Bitmask *node) {
- writer.writeBitmask(node->sig, node->value);
- }
-
- void visit(Struct *node) {
- writer.beginStruct(node->sig);
- for (unsigned i = 0; i < node->sig->num_members; ++i) {
- _visit(node->members[i]);
- }
- writer.endStruct();
- }
-
- void visit(Array *node) {
- writer.beginArray(node->values.size());
- for (std::vector<Value *>::iterator it = node->values.begin(); it != node->values.end(); ++it) {
- _visit(*it);
- }
- writer.endArray();
- }
-
- void visit(Blob *node) {
- writer.writeBlob(node->buf, node->size);
- }
-
- void visit(Pointer *node) {
- writer.writeOpaque((const void *) (size_t) node->value);
- }
-
- void visit(Call *call) {
- unsigned call_no = writer.beginEnter(call->sig);
- for (unsigned i = 0; i < call->args.size(); ++i) {
- if (call->args[i]) {
- writer.beginArg(i);
- _visit(call->args[i]);
- writer.endArg();
- }
- }
- writer.endEnter();
- writer.beginLeave(call_no);
- if (call->ret) {
- writer.beginReturn();
- _visit(call->ret);
- writer.endReturn();
- }
- writer.endLeave();
- }
-};
-
-
-void Writer::writeCall(Call *call) {
- ModelWriter visitor(*this);
- visitor.visit(call);
-}
-
-
-} /* namespace Trace */
-
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * Copyright 2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-
-#include <assert.h>
-#include <stdlib.h>
-
-#include "trace_file.hpp"
-#include "trace_snappyfile.hpp"
-#include "trace_parser.hpp"
-
-
-#define TRACE_VERBOSE 0
-
-
-namespace Trace {
-
-
-Parser::Parser() {
- file = NULL;
- next_call_no = 0;
- version = 0;
-}
-
-
-Parser::~Parser() {
- close();
-}
-
-
-bool Parser::open(const char *filename) {
- assert(!file);
- if (File::isZLibCompressed(filename)) {
- file = new ZLibFile;
- } else {
- file = new SnappyFile;
- }
-
- if (!file->open(filename, File::Read)) {
- return false;
- }
-
- version = read_uint();
- if (version > TRACE_VERSION) {
- std::cerr << "error: unsupported trace format version " << version << "\n";
- return false;
- }
-
- return true;
-}
-
-template <typename Iter>
-inline void
-deleteAll(Iter begin, Iter end)
-{
- while (begin != end) {
- delete *begin;
- ++begin;
- }
-}
-
-template <typename Container>
-inline void
-deleteAll(Container &c)
-{
- deleteAll(c.begin(), c.end());
- c.clear();
-}
-
-void Parser::close(void) {
- if (file) {
- file->close();
- delete file;
- file = NULL;
- }
-
- deleteAll(calls);
-
- // Delete all signature data. Signatures are mere structures which don't
- // own their own memory, so we need to destroy all data we created here.
-
- for (FunctionMap::iterator it = functions.begin(); it != functions.end(); ++it) {
- FunctionSigState *sig = *it;
- if (sig) {
- delete [] sig->name;
- for (unsigned arg = 0; arg < sig->num_args; ++arg) {
- delete [] sig->arg_names[arg];
- }
- delete [] sig->arg_names;
- delete sig;
- }
- }
- functions.clear();
-
- for (StructMap::iterator it = structs.begin(); it != structs.end(); ++it) {
- StructSigState *sig = *it;
- if (sig) {
- delete [] sig->name;
- for (unsigned member = 0; member < sig->num_members; ++member) {
- delete [] sig->member_names[member];
- }
- delete [] sig->member_names;
- delete sig;
- }
- }
- structs.clear();
-
- for (EnumMap::iterator it = enums.begin(); it != enums.end(); ++it) {
- EnumSigState *sig = *it;
- if (sig) {
- delete [] sig->name;
- delete sig;
- }
- }
- enums.clear();
-
- for (BitmaskMap::iterator it = bitmasks.begin(); it != bitmasks.end(); ++it) {
- BitmaskSigState *sig = *it;
- if (sig) {
- for (unsigned flag = 0; flag < sig->num_flags; ++flag) {
- delete [] sig->flags[flag].name;
- }
- delete [] sig->flags;
- delete sig;
- }
- }
- bitmasks.clear();
-}
-
-
-void Parser::getBookmark(ParseBookmark &bookmark) {
- bookmark.offset = file->currentOffset();
- bookmark.next_call_no = next_call_no;
-}
-
-
-void Parser::setBookmark(const ParseBookmark &bookmark) {
- file->setCurrentOffset(bookmark.offset);
- next_call_no = bookmark.next_call_no;
-
- // Simply ignore all pending calls
- deleteAll(calls);
-}
-
-
-Call *Parser::parse_call(Mode mode) {
- do {
- int c = read_byte();
- switch(c) {
- case Trace::EVENT_ENTER:
- parse_enter(mode);
- break;
- case Trace::EVENT_LEAVE:
- return parse_leave(mode);
- default:
- std::cerr << "error: unknown event " << c << "\n";
- exit(1);
- case -1:
- for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
- std::cerr << "warning: incomplete call " << (*it)->name() << "\n";
- std::cerr << **it << "\n";
- }
- return NULL;
- }
- } while(true);
-}
-
-
-/**
- * Helper function to lookup an ID in a vector, resizing the vector if it doesn't fit.
- */
-template<class T>
-T *lookup(std::vector<T *> &map, size_t index) {
- if (index >= map.size()) {
- map.resize(index + 1);
- return NULL;
- } else {
- return map[index];
- }
-}
-
-
-FunctionSig *Parser::parse_function_sig(void) {
- size_t id = read_uint();
-
- FunctionSigState *sig = lookup(functions, id);
-
- if (!sig) {
- /* parse the signature */
- sig = new FunctionSigState;
- sig->id = id;
- sig->name = read_string();
- sig->num_args = read_uint();
- const char **arg_names = new const char *[sig->num_args];
- for (unsigned i = 0; i < sig->num_args; ++i) {
- arg_names[i] = read_string();
- }
- sig->arg_names = arg_names;
- sig->offset = file->currentOffset();
- functions[id] = sig;
- } else if (file->currentOffset() < sig->offset) {
- /* skip over the signature */
- skip_string(); /* name */
- int num_args = read_uint();
- for (unsigned i = 0; i < num_args; ++i) {
- skip_string(); /*arg_name*/
- }
- }
-
- assert(sig);
- return sig;
-}
-
-
-StructSig *Parser::parse_struct_sig() {
- size_t id = read_uint();
-
- StructSigState *sig = lookup(structs, id);
-
- if (!sig) {
- /* parse the signature */
- sig = new StructSigState;
- sig->id = id;
- sig->name = read_string();
- sig->num_members = read_uint();
- const char **member_names = new const char *[sig->num_members];
- for (unsigned i = 0; i < sig->num_members; ++i) {
- member_names[i] = read_string();
- }
- sig->member_names = member_names;
- sig->offset = file->currentOffset();
- structs[id] = sig;
- } else if (file->currentOffset() < sig->offset) {
- /* skip over the signature */
- skip_string(); /* name */
- unsigned num_members = read_uint();
- for (unsigned i = 0; i < num_members; ++i) {
- skip_string(); /* member_name */
- }
- }
-
- assert(sig);
- return sig;
-}
-
-
-EnumSig *Parser::parse_enum_sig() {
- size_t id = read_uint();
-
- EnumSigState *sig = lookup(enums, id);
-
- if (!sig) {
- /* parse the signature */
- sig = new EnumSigState;
- sig->id = id;
- sig->name = read_string();
- Value *value = parse_value();
- sig->value = value->toSInt();
- delete value;
- sig->offset = file->currentOffset();
- enums[id] = sig;
- } else if (file->currentOffset() < sig->offset) {
- /* skip over the signature */
- skip_string(); /*name*/
- scan_value();
- }
-
- assert(sig);
- return sig;
-}
-
-
-BitmaskSig *Parser::parse_bitmask_sig() {
- size_t id = read_uint();
-
- BitmaskSigState *sig = lookup(bitmasks, id);
-
- if (!sig) {
- /* parse the signature */
- sig = new BitmaskSigState;
- sig->id = id;
- sig->num_flags = read_uint();
- BitmaskFlag *flags = new BitmaskFlag[sig->num_flags];
- for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) {
- it->name = read_string();
- it->value = read_uint();
- if (it->value == 0 && it != flags) {
- std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n";
- }
- }
- sig->flags = flags;
- sig->offset = file->currentOffset();
- bitmasks[id] = sig;
- } else if (file->currentOffset() < sig->offset) {
- /* skip over the signature */
- int num_flags = read_uint();
- for (int i = 0; i < num_flags; ++i) {
- skip_string(); /*name */
- skip_uint(); /* value */
- }
- }
-
- assert(sig);
- return sig;
-}
-
-
-void Parser::parse_enter(Mode mode) {
- FunctionSig *sig = parse_function_sig();
-
- Call *call = new Call(sig);
-
- call->no = next_call_no++;
-
- if (parse_call_details(call, mode)) {
- calls.push_back(call);
- } else {
- delete call;
- }
-}
-
-
-Call *Parser::parse_leave(Mode mode) {
- unsigned call_no = read_uint();
- Call *call = NULL;
- for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
- if ((*it)->no == call_no) {
- call = *it;
- calls.erase(it);
- break;
- }
- }
- if (!call) {
- return NULL;
- }
-
- if (parse_call_details(call, mode)) {
- return call;
- } else {
- delete call;
- return NULL;
- }
-}
-
-
-bool Parser::parse_call_details(Call *call, Mode mode) {
- do {
- int c = read_byte();
- switch(c) {
- case Trace::CALL_END:
- return true;
- case Trace::CALL_ARG:
- parse_arg(call, mode);
- break;
- case Trace::CALL_RET:
- call->ret = parse_value(mode);
- break;
- default:
- std::cerr << "error: ("<<call->name()<< ") unknown call detail "
- << c << "\n";
- exit(1);
- case -1:
- return false;
- }
- } while(true);
-}
-
-
-void Parser::parse_arg(Call *call, Mode mode) {
- unsigned index = read_uint();
- Value *value = parse_value(mode);
- if (value) {
- if (index >= call->args.size()) {
- call->args.resize(index + 1);
- }
- call->args[index] = value;
- }
-}
-
-
-Value *Parser::parse_value(void) {
- int c;
- Value *value;
- c = read_byte();
- switch(c) {
- case Trace::TYPE_NULL:
- value = new Null;
- break;
- case Trace::TYPE_FALSE:
- value = new Bool(false);
- break;
- case Trace::TYPE_TRUE:
- value = new Bool(true);
- break;
- case Trace::TYPE_SINT:
- value = parse_sint();
- break;
- case Trace::TYPE_UINT:
- value = parse_uint();
- break;
- case Trace::TYPE_FLOAT:
- value = parse_float();
- break;
- case Trace::TYPE_DOUBLE:
- value = parse_double();
- break;
- case Trace::TYPE_STRING:
- value = parse_string();
- break;
- case Trace::TYPE_ENUM:
- value = parse_enum();
- break;
- case Trace::TYPE_BITMASK:
- value = parse_bitmask();
- break;
- case Trace::TYPE_ARRAY:
- value = parse_array();
- break;
- case Trace::TYPE_STRUCT:
- value = parse_struct();
- break;
- case Trace::TYPE_BLOB:
- value = parse_blob();
- break;
- case Trace::TYPE_OPAQUE:
- value = parse_opaque();
- break;
- default:
- std::cerr << "error: unknown type " << c << "\n";
- exit(1);
- case -1:
- value = NULL;
- break;
- }
-#if TRACE_VERBOSE
- if (value) {
- std::cerr << "\tVALUE " << value << "\n";
- }
-#endif
- return value;
-}
-
-
-void Parser::scan_value(void) {
- int c = read_byte();
- switch(c) {
- case Trace::TYPE_NULL:
- case Trace::TYPE_FALSE:
- case Trace::TYPE_TRUE:
- break;
- case Trace::TYPE_SINT:
- scan_sint();
- break;
- case Trace::TYPE_UINT:
- scan_uint();
- break;
- case Trace::TYPE_FLOAT:
- scan_float();
- break;
- case Trace::TYPE_DOUBLE:
- scan_double();
- break;
- case Trace::TYPE_STRING:
- scan_string();
- break;
- case Trace::TYPE_ENUM:
- scan_enum();
- break;
- case Trace::TYPE_BITMASK:
- scan_bitmask();
- break;
- case Trace::TYPE_ARRAY:
- scan_array();
- break;
- case Trace::TYPE_STRUCT:
- scan_struct();
- break;
- case Trace::TYPE_BLOB:
- scan_blob();
- break;
- case Trace::TYPE_OPAQUE:
- scan_opaque();
- break;
- default:
- std::cerr << "error: unknown type " << c << "\n";
- exit(1);
- case -1:
- break;
- }
-}
-
-
-Value *Parser::parse_sint() {
- return new SInt(-(signed long long)read_uint());
-}
-
-
-void Parser::scan_sint() {
- skip_uint();
-}
-
-
-Value *Parser::parse_uint() {
- return new UInt(read_uint());
-}
-
-
-void Parser::scan_uint() {
- skip_uint();
-}
-
-
-Value *Parser::parse_float() {
- float value;
- file->read(&value, sizeof value);
- return new Float(value);
-}
-
-
-void Parser::scan_float() {
- file->skip(sizeof(float));
-}
-
-
-Value *Parser::parse_double() {
- double value;
- file->read(&value, sizeof value);
- return new Float(value);
-}
-
-
-void Parser::scan_double() {
- file->skip(sizeof(double));
-}
-
-
-Value *Parser::parse_string() {
- return new String(read_string());
-}
-
-
-void Parser::scan_string() {
- skip_string();
-}
-
-
-Value *Parser::parse_enum() {
- EnumSig *sig = parse_enum_sig();
- return new Enum(sig);
-}
-
-
-void Parser::scan_enum() {
- parse_enum_sig();
-}
-
-
-Value *Parser::parse_bitmask() {
- BitmaskSig *sig = parse_bitmask_sig();
-
- unsigned long long value = read_uint();
-
- return new Bitmask(sig, value);
-}
-
-
-void Parser::scan_bitmask() {
- parse_bitmask_sig();
- skip_uint(); /* value */
-}
-
-
-Value *Parser::parse_array(void) {
- size_t len = read_uint();
- Array *array = new Array(len);
- for (size_t i = 0; i < len; ++i) {
- array->values[i] = parse_value();
- }
- return array;
-}
-
-
-void Parser::scan_array(void) {
- size_t len = read_uint();
- for (size_t i = 0; i < len; ++i) {
- scan_value();
- }
-}
-
-
-Value *Parser::parse_blob(void) {
- size_t size = read_uint();
- Blob *blob = new Blob(size);
- if (size) {
- file->read(blob->buf, (unsigned)size);
- }
- return blob;
-}
-
-
-void Parser::scan_blob(void) {
- size_t size = read_uint();
- if (size) {
- file->skip(size);
- }
-}
-
-
-Value *Parser::parse_struct() {
- StructSig *sig = parse_struct_sig();
- Struct *value = new Struct(sig);
-
- for (size_t i = 0; i < sig->num_members; ++i) {
- value->members[i] = parse_value();
- }
-
- return value;
-}
-
-
-void Parser::scan_struct() {
- StructSig *sig = parse_struct_sig();
- for (size_t i = 0; i < sig->num_members; ++i) {
- scan_value();
- }
-}
-
-
-Value *Parser::parse_opaque() {
- unsigned long long addr;
- addr = read_uint();
- return new Pointer(addr);
-}
-
-
-void Parser::scan_opaque() {
- skip_uint();
-}
-
-
-const char * Parser::read_string(void) {
- size_t len = read_uint();
- char * value = new char[len + 1];
- if (len) {
- file->read(value, (unsigned)len);
- }
- value[len] = 0;
-#if TRACE_VERBOSE
- std::cerr << "\tSTRING \"" << value << "\"\n";
-#endif
- return value;
-}
-
-
-void Parser::skip_string(void) {
- size_t len = read_uint();
- file->skip(len);
-}
-
-
-unsigned long long Parser::read_uint(void) {
- unsigned long long value = 0;
- int c;
- unsigned shift = 0;
- do {
- c = file->getc();
- if (c == -1) {
- break;
- }
- value |= (unsigned long long)(c & 0x7f) << shift;
- shift += 7;
- } while(c & 0x80);
-#if TRACE_VERBOSE
- std::cerr << "\tUINT " << value << "\n";
-#endif
- return value;
-}
-
-
-void Parser::skip_uint(void) {
- int c;
- do {
- c = file->getc();
- if (c == -1) {
- break;
- }
- } while(c & 0x80);
-}
-
-
-inline int Parser::read_byte(void) {
- int c = file->getc();
-#if TRACE_VERBOSE
- if (c < 0)
- std::cerr << "\tEOF" << "\n";
- else
- std::cerr << "\tBYTE 0x" << std::hex << c << std::dec << "\n";
-#endif
- return c;
-}
-
-
-inline void Parser::skip_byte(void) {
- file->skip(1);
-}
-
-
-} /* namespace Trace */
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-#ifndef _TRACE_PARSER_HPP_
-#define _TRACE_PARSER_HPP_
-
-
-#include <iostream>
-#include <list>
-
-#include "trace_file.hpp"
-#include "trace_format.hpp"
-#include "trace_model.hpp"
-
-
-namespace Trace {
-
-
-struct ParseBookmark
-{
- File::Offset offset;
- unsigned next_call_no;
-};
-
-
-class Parser
-{
-protected:
- File *file;
-
- enum Mode {
- FULL = 0,
- SCAN,
- SKIP
- };
-
- typedef std::list<Call *> CallList;
- CallList calls;
-
- // Helper template that extends a base signature structure, with additional
- // parsing information.
- template< class T >
- struct SigState : public T {
- // Offset in the file of where signature was defined. It is used when
- // reparsing to determine whether the signature definition is to be
- // expected next or not.
- File::Offset offset;
- };
-
- typedef SigState<FunctionSig> FunctionSigState;
- typedef SigState<StructSig> StructSigState;
- typedef SigState<EnumSig> EnumSigState;
- typedef SigState<BitmaskSig> BitmaskSigState;
-
- typedef std::vector<FunctionSigState *> FunctionMap;
- typedef std::vector<StructSigState *> StructMap;
- typedef std::vector<EnumSigState *> EnumMap;
- typedef std::vector<BitmaskSigState *> BitmaskMap;
-
- FunctionMap functions;
- StructMap structs;
- EnumMap enums;
- BitmaskMap bitmasks;
-
- unsigned next_call_no;
-
-public:
- unsigned long long version;
-
- Parser();
-
- ~Parser();
-
- bool open(const char *filename);
-
- void close(void);
-
- Call *parse_call(void) {
- return parse_call(FULL);
- }
-
- bool supportsOffsets() const
- {
- return file->supportsOffsets();
- }
-
- void getBookmark(ParseBookmark &bookmark);
-
- void setBookmark(const ParseBookmark &bookmark);
-
- int percentRead()
- {
- return file->percentRead();
- }
-
- Call *scan_call() {
- return parse_call(SCAN);
- }
-
-protected:
- Call *parse_call(Mode mode);
-
- FunctionSig *parse_function_sig(void);
- StructSig *parse_struct_sig();
- EnumSig *parse_enum_sig();
- BitmaskSig *parse_bitmask_sig();
-
- Call *parse_Call(Mode mode);
-
- void parse_enter(Mode mode);
-
- Call *parse_leave(Mode mode);
-
- bool parse_call_details(Call *call, Mode mode);
-
- void parse_arg(Call *call, Mode mode);
-
- Value *parse_value(void);
- void scan_value(void);
- inline Value *parse_value(Mode mode) {
- if (mode == FULL) {
- return parse_value();
- } else {
- scan_value();
- return NULL;
- }
- }
-
- Value *parse_sint();
- void scan_sint();
-
- Value *parse_uint();
- void scan_uint();
-
- Value *parse_float();
- void scan_float();
-
- Value *parse_double();
- void scan_double();
-
- Value *parse_string();
- void scan_string();
-
- Value *parse_enum();
- void scan_enum();
-
- Value *parse_bitmask();
- void scan_bitmask();
-
- Value *parse_array(void);
- void scan_array(void);
-
- Value *parse_blob(void);
- void scan_blob(void);
-
- Value *parse_struct();
- void scan_struct();
-
- Value *parse_opaque();
- void scan_opaque();
-
- const char * read_string(void);
- void skip_string(void);
-
- unsigned long long read_uint(void);
- void skip_uint(void);
-
- inline int read_byte(void);
- inline void skip_byte(void);
-};
-
-
-} /* namespace Trace */
-
-#endif /* _TRACE_PARSER_HPP_ */
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2011 Zack Rusin
- * 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.
- *
- **************************************************************************/
-
-
-#include "trace_snappyfile.hpp"
-
-#include <snappy.h>
-
-#include <iostream>
-
-#include <assert.h>
-#include <string.h>
-
-using namespace Trace;
-
-/*
- * Snappy file format.
- * -------------------
- *
- * Snappy at its core is just a compressoin algorithm so we're
- * creating a new file format which uses snappy compression
- * to hold the trace data.
- *
- * The file is composed of a number of chunks, they are:
- * chunk {
- * uint32 - specifying the length of the compressed data
- * compressed data, in little endian
- * }
- * File can contain any number of such chunks.
- * The default size of an uncompressed chunk is specified in
- * SNAPPY_CHUNK_SIZE.
- *
- * Note:
- * Currently the default size for a a to-be-compressed data is
- * 1mb, meaning that the compressed data will be <= 1mb.
- * The reason it's 1mb is because it seems
- * to offer a pretty good compression/disk io speed ratio
- * but that might change.
- *
- */
-
-SnappyFile::SnappyFile(const std::string &filename,
- File::Mode mode)
- : File(),
- m_cache(0),
- m_cachePtr(0),
- m_cacheSize(0)
-{
- size_t maxCompressedLength =
- snappy::MaxCompressedLength(SNAPPY_CHUNK_SIZE);
- m_compressedCache = new char[maxCompressedLength];
-}
-
-SnappyFile::~SnappyFile()
-{
- delete [] m_compressedCache;
- delete [] m_cache;
-}
-
-bool SnappyFile::rawOpen(const std::string &filename, File::Mode mode)
-{
- std::ios_base::openmode fmode = std::fstream::binary;
- if (mode == File::Write) {
- fmode |= (std::fstream::out | std::fstream::trunc);
- createCache(SNAPPY_CHUNK_SIZE);
- } else if (mode == File::Read) {
- fmode |= std::fstream::in;
- }
-
- m_stream.open(filename.c_str(), fmode);
-
- //read in the initial buffer if we're reading
- if (m_stream.is_open() && mode == File::Read) {
- m_stream.seekg(0, std::ios::end);
- m_endPos = m_stream.tellg();
- m_stream.seekg(0, std::ios::beg);
-
- // read the snappy file identifier
- unsigned char byte1, byte2;
- m_stream >> byte1;
- m_stream >> byte2;
- assert(byte1 == SNAPPY_BYTE1 && byte2 == SNAPPY_BYTE2);
-
- flushReadCache();
- } else if (m_stream.is_open() && mode == File::Write) {
- // write the snappy file identifier
- m_stream << SNAPPY_BYTE1;
- m_stream << SNAPPY_BYTE2;
- }
- return m_stream.is_open();
-}
-
-bool SnappyFile::rawWrite(const void *buffer, size_t length)
-{
- if (freeCacheSize() > length) {
- memcpy(m_cachePtr, buffer, length);
- m_cachePtr += length;
- } else if (freeCacheSize() == length) {
- memcpy(m_cachePtr, buffer, length);
- m_cachePtr += length;
- flushWriteCache();
- } else {
- int sizeToWrite = length;
-
- while (sizeToWrite >= freeCacheSize()) {
- int endSize = freeCacheSize();
- int offset = length - sizeToWrite;
- memcpy(m_cachePtr, (const char*)buffer + offset, endSize);
- sizeToWrite -= endSize;
- m_cachePtr += endSize;
- flushWriteCache();
- }
- if (sizeToWrite) {
- int offset = length - sizeToWrite;
- memcpy(m_cachePtr, (const char*)buffer + offset, sizeToWrite);
- m_cachePtr += sizeToWrite;
- }
- }
-
- return true;
-}
-
-bool SnappyFile::rawRead(void *buffer, size_t length)
-{
- if (endOfData()) {
- return false;
- }
-
- if (freeCacheSize() >= length) {
- memcpy(buffer, m_cachePtr, length);
- m_cachePtr += length;
- } else {
- size_t sizeToRead = length;
- size_t offset = 0;
- while (sizeToRead) {
- size_t chunkSize = std::min(freeCacheSize(), sizeToRead);
- offset = length - sizeToRead;
- memcpy((char*)buffer + offset, m_cachePtr, chunkSize);
- m_cachePtr += chunkSize;
- sizeToRead -= chunkSize;
- if (sizeToRead > 0) {
- flushReadCache();
- }
- if (!m_cacheSize) {
- break;
- }
- }
- }
-
- return true;
-}
-
-int SnappyFile::rawGetc()
-{
- int c = 0;
- if (!rawRead(&c, 1))
- return -1;
- return c;
-}
-
-void SnappyFile::rawClose()
-{
- if (m_mode == File::Write) {
- flushWriteCache();
- }
- m_stream.close();
- delete [] m_cache;
- m_cache = NULL;
- m_cachePtr = NULL;
-}
-
-void SnappyFile::rawFlush()
-{
- assert(m_mode == File::Write);
- flushWriteCache();
- m_stream.flush();
-}
-
-void SnappyFile::flushWriteCache()
-{
- size_t inputLength = usedCacheSize();
-
- if (inputLength) {
- size_t compressedLength;
-
- ::snappy::RawCompress(m_cache, inputLength,
- m_compressedCache, &compressedLength);
-
- writeCompressedLength(compressedLength);
- m_stream.write(m_compressedCache, compressedLength);
- m_cachePtr = m_cache;
- }
- assert(m_cachePtr == m_cache);
-}
-
-void SnappyFile::flushReadCache(size_t skipLength)
-{
- //assert(m_cachePtr == m_cache + m_cacheSize);
- m_currentOffset.chunk = m_stream.tellg();
- size_t compressedLength;
- compressedLength = readCompressedLength();
-
- if (compressedLength) {
- m_stream.read((char*)m_compressedCache, compressedLength);
- ::snappy::GetUncompressedLength(m_compressedCache, compressedLength,
- &m_cacheSize);
- createCache(m_cacheSize);
- if (skipLength < m_cacheSize) {
- ::snappy::RawUncompress(m_compressedCache, compressedLength,
- m_cache);
- }
- } else {
- createCache(0);
- }
-}
-
-void SnappyFile::createCache(size_t size)
-{
- // TODO: only re-allocate if the current buffer is not big enough
-
- if (m_cache) {
- delete [] m_cache;
- }
-
- if (size) {
- m_cache = new char[size];
- } else {
- m_cache = NULL;
- }
-
- m_cachePtr = m_cache;
- m_cacheSize = size;
-}
-
-void SnappyFile::writeCompressedLength(size_t length)
-{
- unsigned char buf[4];
- buf[0] = length & 0xff; length >>= 8;
- buf[1] = length & 0xff; length >>= 8;
- buf[2] = length & 0xff; length >>= 8;
- buf[3] = length & 0xff; length >>= 8;
- assert(length == 0);
- m_stream.write((const char *)buf, sizeof buf);
-}
-
-size_t SnappyFile::readCompressedLength()
-{
- unsigned char buf[4];
- size_t length;
- m_stream.read((char *)buf, sizeof buf);
- if (m_stream.fail()) {
- length = 0;
- } else {
- length = (size_t)buf[0];
- length |= ((size_t)buf[1] << 8);
- length |= ((size_t)buf[2] << 16);
- length |= ((size_t)buf[3] << 24);
- }
- return length;
-}
-
-bool SnappyFile::supportsOffsets() const
-{
- return true;
-}
-
-File::Offset SnappyFile::currentOffset()
-{
- m_currentOffset.offsetInChunk = m_cachePtr - m_cache;
- return m_currentOffset;
-}
-
-void SnappyFile::setCurrentOffset(const File::Offset &offset)
-{
- // to remove eof bit
- m_stream.clear();
- // seek to the start of a chunk
- m_stream.seekg(offset.chunk, std::ios::beg);
- // load the chunk
- flushReadCache();
- assert(m_cacheSize >= offset.offsetInChunk);
- // seek within our cache to the correct location within the chunk
- m_cachePtr = m_cache + offset.offsetInChunk;
-
-}
-
-bool SnappyFile::rawSkip(size_t length)
-{
- if (endOfData()) {
- return false;
- }
-
- if (freeCacheSize() >= length) {
- m_cachePtr += length;
- } else {
- size_t sizeToRead = length;
- while (sizeToRead) {
- size_t chunkSize = std::min(freeCacheSize(), sizeToRead);
- m_cachePtr += chunkSize;
- sizeToRead -= chunkSize;
- if (sizeToRead > 0) {
- flushReadCache(sizeToRead);
- }
- if (!m_cacheSize) {
- break;
- }
- }
- }
-
- return true;
-}
-
-int SnappyFile::rawPercentRead()
-{
- return 100 * (double(m_stream.tellg()) / double(m_endPos));
-}
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2011 Zack Rusin
- * 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.
- *
- **************************************************************************/
-
-
-#ifndef TRACE_SNAPPYFILE_HPP
-#define TRACE_SNAPPYFILE_HPP
-
-#include <assert.h>
-
-#include "trace_file.hpp"
-
-#include <string>
-#include <fstream>
-
-namespace snappy {
- class File;
-}
-
-namespace Trace {
-
-#define SNAPPY_CHUNK_SIZE (1 * 1024 * 1024)
-
-#define SNAPPY_BYTE1 'a'
-#define SNAPPY_BYTE2 't'
-
-
-class SnappyFile : public File {
-public:
- SnappyFile(const std::string &filename = std::string(),
- File::Mode mode = File::Read);
- virtual ~SnappyFile();
-
- virtual bool supportsOffsets() const;
- virtual File::Offset currentOffset();
- virtual void setCurrentOffset(const File::Offset &offset);
-protected:
- virtual bool rawOpen(const std::string &filename, File::Mode mode);
- virtual bool rawWrite(const void *buffer, size_t length);
- virtual bool rawRead(void *buffer, size_t length);
- virtual int rawGetc();
- virtual void rawClose();
- virtual void rawFlush();
- virtual bool rawSkip(size_t length);
- virtual int rawPercentRead();
-
-private:
- inline size_t usedCacheSize() const
- {
- assert(m_cachePtr >= m_cache);
- return m_cachePtr - m_cache;
- }
- inline size_t freeCacheSize() const
- {
- assert(m_cacheSize >= usedCacheSize());
- if (m_cacheSize > 0) {
- return m_cacheSize - usedCacheSize();
- } else {
- return 0;
- }
- }
- inline bool endOfData() const
- {
- return m_stream.eof() && freeCacheSize() == 0;
- }
- void flushWriteCache();
- void flushReadCache(size_t skipLength = 0);
- void createCache(size_t size);
- void writeCompressedLength(size_t length);
- size_t readCompressedLength();
-private:
- std::fstream m_stream;
- char *m_cache;
- char *m_cachePtr;
- size_t m_cacheSize;
-
- char *m_compressedCache;
-
- File::Offset m_currentOffset;
- std::streampos m_endPos;
-};
-
-}
-
-#endif // TRACE_SNAPPYFILE_HPP
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2007-2009 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-
-#include <assert.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "os.hpp"
-#include "trace_writer.hpp"
-#include "trace_snappyfile.hpp"
-#include "trace_format.hpp"
-
-
-namespace Trace {
-
-
-Writer::Writer() :
- call_no(0)
-{
- m_file = new Trace::SnappyFile;
- close();
-}
-
-Writer::~Writer()
-{
- close();
- delete m_file;
- m_file = NULL;
-}
-
-void
-Writer::close(void) {
- m_file->close();
-}
-
-bool
-Writer::open(const char *filename) {
- close();
-
- if (!m_file->open(filename, File::Write)) {
- return false;
- }
-
- call_no = 0;
- functions.clear();
- structs.clear();
- enums.clear();
- bitmasks.clear();
-
- _writeUInt(TRACE_VERSION);
-
- return true;
-}
-
-void inline
-Writer::_write(const void *sBuffer, size_t dwBytesToWrite) {
- m_file->write(sBuffer, dwBytesToWrite);
-}
-
-void inline
-Writer::_writeByte(char c) {
- _write(&c, 1);
-}
-
-void inline
-Writer::_writeUInt(unsigned long long value) {
- char buf[2 * sizeof value];
- unsigned len;
-
- len = 0;
- do {
- assert(len < sizeof buf);
- buf[len] = 0x80 | (value & 0x7f);
- value >>= 7;
- ++len;
- } while (value);
-
- assert(len);
- buf[len - 1] &= 0x7f;
-
- _write(buf, len);
-}
-
-void inline
-Writer::_writeFloat(float value) {
- assert(sizeof value == 4);
- _write((const char *)&value, sizeof value);
-}
-
-void inline
-Writer::_writeDouble(double value) {
- assert(sizeof value == 8);
- _write((const char *)&value, sizeof value);
-}
-
-void inline
-Writer::_writeString(const char *str) {
- size_t len = strlen(str);
- _writeUInt(len);
- _write(str, len);
-}
-
-inline bool lookup(std::vector<bool> &map, size_t index) {
- if (index >= map.size()) {
- map.resize(index + 1);
- return false;
- } else {
- return map[index];
- }
-}
-
-unsigned Writer::beginEnter(const FunctionSig *sig) {
- _writeByte(Trace::EVENT_ENTER);
- _writeUInt(sig->id);
- if (!lookup(functions, sig->id)) {
- _writeString(sig->name);
- _writeUInt(sig->num_args);
- for (unsigned i = 0; i < sig->num_args; ++i) {
- _writeString(sig->arg_names[i]);
- }
- functions[sig->id] = true;
- }
-
- return call_no++;
-}
-
-void Writer::endEnter(void) {
- _writeByte(Trace::CALL_END);
-}
-
-void Writer::beginLeave(unsigned call) {
- _writeByte(Trace::EVENT_LEAVE);
- _writeUInt(call);
-}
-
-void Writer::endLeave(void) {
- _writeByte(Trace::CALL_END);
-}
-
-void Writer::beginArg(unsigned index) {
- _writeByte(Trace::CALL_ARG);
- _writeUInt(index);
-}
-
-void Writer::beginReturn(void) {
- _writeByte(Trace::CALL_RET);
-}
-
-void Writer::beginArray(size_t length) {
- _writeByte(Trace::TYPE_ARRAY);
- _writeUInt(length);
-}
-
-void Writer::beginStruct(const StructSig *sig) {
- _writeByte(Trace::TYPE_STRUCT);
- _writeUInt(sig->id);
- if (!lookup(structs, sig->id)) {
- _writeString(sig->name);
- _writeUInt(sig->num_members);
- for (unsigned i = 0; i < sig->num_members; ++i) {
- _writeString(sig->member_names[i]);
- }
- structs[sig->id] = true;
- }
-}
-
-void Writer::writeBool(bool value) {
- _writeByte(value ? Trace::TYPE_TRUE : Trace::TYPE_FALSE);
-}
-
-void Writer::writeSInt(signed long long value) {
- if (value < 0) {
- _writeByte(Trace::TYPE_SINT);
- _writeUInt(-value);
- } else {
- _writeByte(Trace::TYPE_UINT);
- _writeUInt(value);
- }
-}
-
-void Writer::writeUInt(unsigned long long value) {
- _writeByte(Trace::TYPE_UINT);
- _writeUInt(value);
-}
-
-void Writer::writeFloat(float value) {
- _writeByte(Trace::TYPE_FLOAT);
- _writeFloat(value);
-}
-
-void Writer::writeDouble(double value) {
- _writeByte(Trace::TYPE_DOUBLE);
- _writeDouble(value);
-}
-
-void Writer::writeString(const char *str) {
- if (!str) {
- Writer::writeNull();
- return;
- }
- _writeByte(Trace::TYPE_STRING);
- _writeString(str);
-}
-
-void Writer::writeString(const char *str, size_t len) {
- if (!str) {
- Writer::writeNull();
- return;
- }
- _writeByte(Trace::TYPE_STRING);
- _writeUInt(len);
- _write(str, len);
-}
-
-void Writer::writeWString(const wchar_t *str) {
- if (!str) {
- Writer::writeNull();
- return;
- }
- _writeByte(Trace::TYPE_STRING);
- _writeString("<wide-string>");
-}
-
-void Writer::writeBlob(const void *data, size_t size) {
- if (!data) {
- Writer::writeNull();
- return;
- }
- _writeByte(Trace::TYPE_BLOB);
- _writeUInt(size);
- if (size) {
- _write(data, size);
- }
-}
-
-void Writer::writeEnum(const EnumSig *sig) {
- _writeByte(Trace::TYPE_ENUM);
- _writeUInt(sig->id);
- if (!lookup(enums, sig->id)) {
- _writeString(sig->name);
- Writer::writeSInt(sig->value);
- enums[sig->id] = true;
- }
-}
-
-void Writer::writeBitmask(const BitmaskSig *sig, unsigned long long value) {
- _writeByte(Trace::TYPE_BITMASK);
- _writeUInt(sig->id);
- if (!lookup(bitmasks, sig->id)) {
- _writeUInt(sig->num_flags);
- for (unsigned i = 0; i < sig->num_flags; ++i) {
- if (i != 0 && sig->flags[i].value == 0) {
- OS::DebugMessage("apitrace: warning: sig %s is zero but is not first flag\n", sig->flags[i].name);
- }
- _writeString(sig->flags[i].name);
- _writeUInt(sig->flags[i].value);
- }
- bitmasks[sig->id] = true;
- }
- _writeUInt(value);
-}
-
-void Writer::writeNull(void) {
- _writeByte(Trace::TYPE_NULL);
-}
-
-void Writer::writeOpaque(const void *addr) {
- if (!addr) {
- Writer::writeNull();
- return;
- }
- _writeByte(Trace::TYPE_OPAQUE);
- _writeUInt((size_t)addr);
-}
-
-
-} /* namespace Trace */
-
+++ /dev/null
-/**************************************************************************
- *
- * Copyright 2007-2010 VMware, Inc.
- * 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.
- *
- **************************************************************************/
-
-/*
- * Trace writing functions.
- */
-
-#ifndef _TRACE_WRITER_HPP_
-#define _TRACE_WRITER_HPP_
-
-
-#include <stddef.h>
-
-#include <vector>
-
-#include "trace_model.hpp"
-
-
-namespace Trace {
- class File;
-
- class Writer {
- protected:
- File *m_file;
- unsigned call_no;
-
- std::vector<bool> functions;
- std::vector<bool> structs;
- std::vector<bool> enums;
- std::vector<bool> bitmasks;
-
- public:
- Writer();
- ~Writer();
-
- bool open(const char *filename);
- void close(void);
-
- unsigned beginEnter(const FunctionSig *sig);
- void endEnter(void);
-
- void beginLeave(unsigned call);
- void endLeave(void);
-
- void beginArg(unsigned index);
- inline void endArg(void) {}
-
- void beginReturn(void);
- inline void endReturn(void) {}
-
- void beginArray(size_t length);
- inline void endArray(void) {}
-
- inline void beginElement(void) {}
- inline void endElement(void) {}
-
- void beginStruct(const StructSig *sig);
- inline void endStruct(void) {}
-
- void writeBool(bool value);
- void writeSInt(signed long long value);
- void writeUInt(unsigned long long value);
- void writeFloat(float value);
- void writeDouble(double value);
- void writeString(const char *str);
- void writeString(const char *str, size_t size);
- void writeWString(const wchar_t *str);
- void writeBlob(const void *data, size_t size);
- void writeEnum(const EnumSig *sig);
- void writeBitmask(const BitmaskSig *sig, unsigned long long value);
- void writeNull(void);
- void writeOpaque(const void *ptr);
-
- void writeCall(Call *call);
-
- protected:
- void inline _write(const void *sBuffer, size_t dwBytesToWrite);
- void inline _writeByte(char c);
- void inline _writeUInt(unsigned long long value);
- void inline _writeFloat(float value);
- void inline _writeDouble(double value);
- void inline _writeString(const char *str);
-
- };
-
- /**
- * A specialized Writer class, mean to trace the current process.
- *
- * In particular:
- * - it creates a trace file based on the current process name
- * - uses mutexes to allow tracing from multiple threades
- * - flushes the output to ensure the last call is traced in event of
- * abnormal termination
- */
- class LocalWriter : public Writer {
- protected:
- int acquired;
-
- public:
- /**
- * Should never called directly -- use localWriter singleton below instead.
- */
- LocalWriter();
- ~LocalWriter();
-
- void open(void);
-
- unsigned beginEnter(const FunctionSig *sig);
- void endEnter(void);
-
- void beginLeave(unsigned call);
- void endLeave(void);
-
- void flush(void);
- };
-
- /**
- * Singleton.
- */
- extern LocalWriter localWriter;
-}
-
-#endif /* _TRACE_WRITER_HPP_ */