<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#include <seastar/core/thread.hh>
#include <seastar/core/do_with.hh>
#include <seastar/testing/test_case.hh>
#include <seastar/testing/thread_test_case.hh>
#include <seastar/core/sstring.hh>
#include <seastar/core/semaphore.hh>
#include <seastar/core/do_with.hh>
#include <seastar/core/future-util.hh>
#include <seastar/core/sleep.hh>
#include <sys/mman.h>
#include <sys/signal.h>

using namespace seastar;
using namespace std::chrono_literals;

SEASTAR_TEST_CASE(test_thread_1) {
    return do_with(sstring(), [] (sstring& x) {
        auto t1 = new thread([&x] {
            x = "abc";
        });
        return t1->join().then([&x, t1] {
            BOOST_REQUIRE_EQUAL(x, "abc");
            delete t1;
        });
    });
}

SEASTAR_TEST_CASE(test_thread_2) {
    struct tmp {
        std::vector<thread> threads;
        semaphore sem1{0};
        semaphore sem2{0};
        int counter = 0;
        void thread_fn() {
            sem1.wait(1).get();
            ++counter;
            sem2.signal(1);
        }
    };
    return do_with(tmp(), [] (tmp& x) {
        auto n = 10;
        for (int i = 0; i < n; ++i) {
            x.threads.emplace_back(std::bind(&tmp::thread_fn, &x));
        }
        BOOST_REQUIRE_EQUAL(x.counter, 0);
        x.sem1.signal(n);
        return x.sem2.wait(n).then([&x, n] {
            BOOST_REQUIRE_EQUAL(x.counter, n);
            return parallel_for_each(x.threads.begin(), x.threads.end(), std::mem_fn(&thread::join));
        });
    });
}

SEASTAR_TEST_CASE(test_thread_async) {
    sstring x = "x";
    sstring y = "y";
    auto concat = [] (sstring x, sstring y) {
        sleep(10ms).get();
        return x + y;
    };
    return async(concat, x, y).then([] (sstring xy) {
        BOOST_REQUIRE_EQUAL(xy, "xy");
    });
}

SEASTAR_TEST_CASE(test_thread_async_immed) {
    return async([] { return 3; }).then([] (int three) {
        BOOST_REQUIRE_EQUAL(three, 3);
    });
}

SEASTAR_TEST_CASE(test_thread_async_nested) {
    return async([] {
        return async([] {
            return 3;
        }).get0();
    }).then([] (int three) {
        BOOST_REQUIRE_EQUAL(three, 3);
    });
}

void compute(float& result, bool& done, uint64_t& ctr) {
    while (!done) {
        for (int n = 0; n < 10000; ++n) {
            result += 1 / (result + 1);
            ++ctr;
        }
        thread::yield();
    }
}

#if defined(SEASTAR_ASAN_ENABLED) && defined(SEASTAR_HAVE_ASAN_FIBER_SUPPORT)
volatile int force_write;
volatile void* shut_up_gcc;

[[gnu::noinline]]
void throw_exception() {
    volatile char buf[1024];
    shut_up_gcc = &buf;
    for (int i = 0; i < 1024; i++) {
        buf[i] = force_write;
    }
    throw 1;
}

[[gnu::noinline]]
void use_stack() {
    volatile char buf[2 * 1024];
    shut_up_gcc = &buf;
    for (int i = 0; i < 2 * 1024; i++) {
        buf[i] = force_write;
    }
}

SEASTAR_TEST_CASE(test_asan_false_positive) {
    return async([] {
        try {
            throw_exception();
        } catch (...) {
            use_stack();
        }
    });
}
#endif

SEASTAR_THREAD_TEST_CASE_EXPECTED_FAILURES(abc, 2) {
    BOOST_TEST(false);
    BOOST_TEST(false);
}

SEASTAR_TEST_CASE(test_thread_custom_stack_size) {
    sstring x = "x";
    sstring y = "y";
    auto concat = [] (sstring x, sstring y) {
        sleep(10ms).get();
        return x + y;
    };
    thread_attributes attr;
    attr.stack_size = 16384;
    return async(attr, concat, x, y).then([] (sstring xy) {
        BOOST_REQUIRE_EQUAL(xy, "xy");
    });
}

// The test case uses x86_64 specific signal handler info
#if defined(SEASTAR_THREAD_STACK_GUARDS) && defined(__x86_64__)
struct test_thread_custom_stack_size_failure : public seastar::testing::seastar_test {
    const char* get_test_file() override { return __FILE__; }
    const char* get_name() override { return "test_thread_custom_stack_size_failure"; }
    int get_expected_failures() override { return 0; } \
    seastar::future<> run_test_case() override;
};

static test_thread_custom_stack_size_failure test_thread_custom_stack_size_failure_instance;
static thread_local volatile bool stack_guard_bypassed = false;

static int get_mprotect_flags(void* ctx) {
    int flags;
    ucontext_t* context = reinterpret_cast<ucontext_t*>(ctx);
    if (context->uc_mcontext.gregs[REG_ERR] & 0x2) {
        flags = PROT_READ | PROT_WRITE;
    } else {
        flags = PROT_READ;
    }
    return flags;
}

static void* pagealign(void* ptr, size_t page_size) {
    static const int pageshift = ffs(page_size) - 1;
    return reinterpret_cast<void*>(((reinterpret_cast<intptr_t>((ptr)) >> pageshift) << pageshift));
}

static thread_local struct sigaction default_old_sigsegv_handler;

static void bypass_stack_guard(int sig, siginfo_t* si, void* ctx) {
    assert(sig == SIGSEGV);
    int flags = get_mprotect_flags(ctx);
    stack_guard_bypassed = (flags & PROT_WRITE);
    if (!stack_guard_bypassed) {
        return;
    }
    size_t page_size = getpagesize();
    auto mp_result = mprotect(pagealign(si->si_addr, page_size), page_size, PROT_READ | PROT_WRITE);
    assert(mp_result == 0);
}

// This test will fail with a regular stack size, because we only probe
// around 10KiB of data, and the stack guard resides after 128'th KiB.
seastar::future<> test_thread_custom_stack_size_failure::run_test_case() {
    sstring x = "x";
    sstring y = "y";

    // Catch segmentation fault once:
    struct sigaction sa{};
    sa.sa_sigaction = &bypass_stack_guard;
    sa.sa_flags = SA_SIGINFO;
    auto ret = sigaction(SIGSEGV, &sa, &default_old_sigsegv_handler);
    if (ret) {
        throw std::system_error(ret, std::system_category());
    }

    auto concat = [] (sstring x, sstring y) {
        sleep(10ms).get();
        // Probe the stack by writing to it in intervals of 1024,
        // until we hit a write fault. In order not to ruin anything,
        // the "write" uses data it just read from the address.
        volatile char* mem = reinterpret_cast<volatile char*>(&x);
        for (int i = 0; i < 20; ++i) {
            mem[i*-1024] = char(mem[i*-1024]);
            if (stack_guard_bypassed) {
                break;
            }
        }
        return x + y;
    };
    thread_attributes attr;
    attr.stack_size = 16384;
    return async(attr, concat, x, y).then([] (sstring xy) {
        BOOST_REQUIRE_EQUAL(xy, "xy");
        BOOST_REQUIRE(stack_guard_bypassed);
        auto ret = sigaction(SIGSEGV, &default_old_sigsegv_handler, nullptr);
        if (ret) {
            throw std::system_error(ret, std::system_category());
        }
    }).then([concat, x, y] {
        // The same function with a default stack will not trigger
        // a segfault, because its stack is much bigger than 10KiB
        return async(concat, x, y).then([] (sstring xy) {
            BOOST_REQUIRE_EQUAL(xy, "xy");
        });
    });
}
#endif // SEASTAR_THREAD_STACK_GUARDS && __x86_64__
<commit_msg>thread_test: Disable test that fails with valgrind<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#include <seastar/core/thread.hh>
#include <seastar/core/do_with.hh>
#include <seastar/testing/test_case.hh>
#include <seastar/testing/thread_test_case.hh>
#include <seastar/core/sstring.hh>
#include <seastar/core/semaphore.hh>
#include <seastar/core/do_with.hh>
#include <seastar/core/future-util.hh>
#include <seastar/core/sleep.hh>
#include <sys/mman.h>
#include <sys/signal.h>

#include <valgrind/valgrind.h>

using namespace seastar;
using namespace std::chrono_literals;

SEASTAR_TEST_CASE(test_thread_1) {
    return do_with(sstring(), [] (sstring& x) {
        auto t1 = new thread([&x] {
            x = "abc";
        });
        return t1->join().then([&x, t1] {
            BOOST_REQUIRE_EQUAL(x, "abc");
            delete t1;
        });
    });
}

SEASTAR_TEST_CASE(test_thread_2) {
    struct tmp {
        std::vector<thread> threads;
        semaphore sem1{0};
        semaphore sem2{0};
        int counter = 0;
        void thread_fn() {
            sem1.wait(1).get();
            ++counter;
            sem2.signal(1);
        }
    };
    return do_with(tmp(), [] (tmp& x) {
        auto n = 10;
        for (int i = 0; i < n; ++i) {
            x.threads.emplace_back(std::bind(&tmp::thread_fn, &x));
        }
        BOOST_REQUIRE_EQUAL(x.counter, 0);
        x.sem1.signal(n);
        return x.sem2.wait(n).then([&x, n] {
            BOOST_REQUIRE_EQUAL(x.counter, n);
            return parallel_for_each(x.threads.begin(), x.threads.end(), std::mem_fn(&thread::join));
        });
    });
}

SEASTAR_TEST_CASE(test_thread_async) {
    sstring x = "x";
    sstring y = "y";
    auto concat = [] (sstring x, sstring y) {
        sleep(10ms).get();
        return x + y;
    };
    return async(concat, x, y).then([] (sstring xy) {
        BOOST_REQUIRE_EQUAL(xy, "xy");
    });
}

SEASTAR_TEST_CASE(test_thread_async_immed) {
    return async([] { return 3; }).then([] (int three) {
        BOOST_REQUIRE_EQUAL(three, 3);
    });
}

SEASTAR_TEST_CASE(test_thread_async_nested) {
    return async([] {
        return async([] {
            return 3;
        }).get0();
    }).then([] (int three) {
        BOOST_REQUIRE_EQUAL(three, 3);
    });
}

void compute(float& result, bool& done, uint64_t& ctr) {
    while (!done) {
        for (int n = 0; n < 10000; ++n) {
            result += 1 / (result + 1);
            ++ctr;
        }
        thread::yield();
    }
}

#if defined(SEASTAR_ASAN_ENABLED) && defined(SEASTAR_HAVE_ASAN_FIBER_SUPPORT)
volatile int force_write;
volatile void* shut_up_gcc;

[[gnu::noinline]]
void throw_exception() {
    volatile char buf[1024];
    shut_up_gcc = &buf;
    for (int i = 0; i < 1024; i++) {
        buf[i] = force_write;
    }
    throw 1;
}

[[gnu::noinline]]
void use_stack() {
    volatile char buf[2 * 1024];
    shut_up_gcc = &buf;
    for (int i = 0; i < 2 * 1024; i++) {
        buf[i] = force_write;
    }
}

SEASTAR_TEST_CASE(test_asan_false_positive) {
    return async([] {
        try {
            throw_exception();
        } catch (...) {
            use_stack();
        }
    });
}
#endif

SEASTAR_THREAD_TEST_CASE_EXPECTED_FAILURES(abc, 2) {
    BOOST_TEST(false);
    BOOST_TEST(false);
}

SEASTAR_TEST_CASE(test_thread_custom_stack_size) {
    sstring x = "x";
    sstring y = "y";
    auto concat = [] (sstring x, sstring y) {
        sleep(10ms).get();
        return x + y;
    };
    thread_attributes attr;
    attr.stack_size = 16384;
    return async(attr, concat, x, y).then([] (sstring xy) {
        BOOST_REQUIRE_EQUAL(xy, "xy");
    });
}

// The test case uses x86_64 specific signal handler info
#if defined(SEASTAR_THREAD_STACK_GUARDS) && defined(__x86_64__)
struct test_thread_custom_stack_size_failure : public seastar::testing::seastar_test {
    const char* get_test_file() override { return __FILE__; }
    const char* get_name() override { return "test_thread_custom_stack_size_failure"; }
    int get_expected_failures() override { return 0; } \
    seastar::future<> run_test_case() override;
};

static test_thread_custom_stack_size_failure test_thread_custom_stack_size_failure_instance;
static thread_local volatile bool stack_guard_bypassed = false;

static int get_mprotect_flags(void* ctx) {
    int flags;
    ucontext_t* context = reinterpret_cast<ucontext_t*>(ctx);
    if (context->uc_mcontext.gregs[REG_ERR] & 0x2) {
        flags = PROT_READ | PROT_WRITE;
    } else {
        flags = PROT_READ;
    }
    return flags;
}

static void* pagealign(void* ptr, size_t page_size) {
    static const int pageshift = ffs(page_size) - 1;
    return reinterpret_cast<void*>(((reinterpret_cast<intptr_t>((ptr)) >> pageshift) << pageshift));
}

static thread_local struct sigaction default_old_sigsegv_handler;

static void bypass_stack_guard(int sig, siginfo_t* si, void* ctx) {
    assert(sig == SIGSEGV);
    int flags = get_mprotect_flags(ctx);
    stack_guard_bypassed = (flags & PROT_WRITE);
    if (!stack_guard_bypassed) {
        return;
    }
    size_t page_size = getpagesize();
    auto mp_result = mprotect(pagealign(si->si_addr, page_size), page_size, PROT_READ | PROT_WRITE);
    assert(mp_result == 0);
}

// This test will fail with a regular stack size, because we only probe
// around 10KiB of data, and the stack guard resides after 128'th KiB.
seastar::future<> test_thread_custom_stack_size_failure::run_test_case() {
    if (RUNNING_ON_VALGRIND) {
        return make_ready_future<>();
    }

    sstring x = "x";
    sstring y = "y";

    // Catch segmentation fault once:
    struct sigaction sa{};
    sa.sa_sigaction = &bypass_stack_guard;
    sa.sa_flags = SA_SIGINFO;
    auto ret = sigaction(SIGSEGV, &sa, &default_old_sigsegv_handler);
    if (ret) {
        throw std::system_error(ret, std::system_category());
    }

    auto concat = [] (sstring x, sstring y) {
        sleep(10ms).get();
        // Probe the stack by writing to it in intervals of 1024,
        // until we hit a write fault. In order not to ruin anything,
        // the "write" uses data it just read from the address.
        volatile char* mem = reinterpret_cast<volatile char*>(&x);
        for (int i = 0; i < 20; ++i) {
            mem[i*-1024] = char(mem[i*-1024]);
            if (stack_guard_bypassed) {
                break;
            }
        }
        return x + y;
    };
    thread_attributes attr;
    attr.stack_size = 16384;
    return async(attr, concat, x, y).then([] (sstring xy) {
        BOOST_REQUIRE_EQUAL(xy, "xy");
        BOOST_REQUIRE(stack_guard_bypassed);
        auto ret = sigaction(SIGSEGV, &default_old_sigsegv_handler, nullptr);
        if (ret) {
            throw std::system_error(ret, std::system_category());
        }
    }).then([concat, x, y] {
        // The same function with a default stack will not trigger
        // a segfault, because its stack is much bigger than 10KiB
        return async(concat, x, y).then([] (sstring xy) {
            BOOST_REQUIRE_EQUAL(xy, "xy");
        });
    });
}
#endif // SEASTAR_THREAD_STACK_GUARDS && __x86_64__
<|endoftext|>


<commit_before>#include "PreMatchState.h"

#include <SFML\Graphics\RenderWindow.hpp>
#include <SFML\Network\UdpSocket.hpp>
#include <SFML\Network\Packet.hpp>

#include "..\..\Common\Protocol.h"

PreMatchState::PreMatchState(StateStack& stateStack, Context& context, States::ID id)
	:
	State(stateStack, context, id)
{
	m_statusText.setFont(*context.font);
	m_statusText.setColor(sf::Color::Red);
	m_statusText.setPosition(100, 100);
	m_statusText.setString("Waiting for match...");
}

PreMatchState::~PreMatchState()
{
}

bool PreMatchState::update(sf::Time & p_deltaTime)
{
	sf::Packet packet;
	sf::IpAddress address;
	unsigned short port;
	while (getContext()->socket->receive(packet, address, port) == sf::Socket::Done)
	{
		int type, time;
		packet >> time >> type;

		if ((cn::PacketType)type == cn::MatchStart)
			requestStackPop();
	}
	return false;
}

bool PreMatchState::draw()
{
	getContext()->window->clear(sf::Color::Black);
	getContext()->window->draw(m_statusText);
	return false;
}

bool PreMatchState::handleEvents(const sf::Event& event)
{
	return false;
}<commit_msg>Ping fix in PreMatchState<commit_after>#include "PreMatchState.h"

#include <SFML\Graphics\RenderWindow.hpp>
#include <SFML\Network\UdpSocket.hpp>
#include <SFML\Network\Packet.hpp>

#include "..\..\Common\Protocol.h"

PreMatchState::PreMatchState(StateStack& stateStack, Context& context, States::ID id)
	:
	State(stateStack, context, id)
{
	m_statusText.setFont(*context.font);
	m_statusText.setColor(sf::Color::Red);
	m_statusText.setPosition(100, 100);
	m_statusText.setString("Waiting for match...");
}

PreMatchState::~PreMatchState()
{
}

bool PreMatchState::update(sf::Time & p_deltaTime)
{
	sf::Packet packet;
	sf::IpAddress address;
	unsigned short port;
	while (getContext()->socket->receive(packet, address, port) == sf::Socket::Done)
	{
		int type, time;
		packet >> time >> type;

		if ((cn::PacketType)type == cn::MatchStart)
		{
			requestStackPop();
		}
		else if ((cn::PacketType)type == cn::Ping)
		{
			sf::Packet pingPacket;
			pingPacket << 0 << cn::Ping << m_name;
			m_socket.send(pingPacket, address, port);
		}

	}
	return false;
}

bool PreMatchState::draw()
{
	getContext()->window->clear(sf::Color::Black);
	getContext()->window->draw(m_statusText);
	return false;
}

bool PreMatchState::handleEvents(const sf::Event& event)
{
	return false;
}<|endoftext|>


<commit_before>/******************************************************************************
 *  Copyright (c) 2014 Jinming Hu
 *  Distributed under the MIT license
 *  (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT)
 *
 *  Project:
 *  Filename: db_tablemgr_test.cc
 *  Version: 1.0
 *  Author: Jinming Hu
 *  E-mail: hjm211324@gmail.com
 *  Date: Oct. 24, 2014
 *  Time: 09:44:22
 *  Description:
 *****************************************************************************/
#include <iostream>
#include <cassert>
#include "../src/db_tablemanager.h"
#include "../src/db_fields.h"

int main() {
    using namespace std;
    using namespace Database;

    DBTableManager table;

    DBFields fields;
    /*
    static constexpr uint64 TYPE_INT8    = 0;
    static constexpr uint64 TYPE_UINT8   = 1;
    static constexpr uint64 TYPE_INT16   = 2;
    static constexpr uint64 TYPE_UINT16  = 3;
    static constexpr uint64 TYPE_INT32   = 4;
    static constexpr uint64 TYPE_UINT32  = 5;
    static constexpr uint64 TYPE_INT64   = 6;
    static constexpr uint64 TYPE_UINT64  = 7;
    static constexpr uint64 TYPE_BOOL    = 8;
    static constexpr uint64 TYPE_CHAR    = 9;
    static constexpr uint64 TYPE_UCHAR   = 10;
    static constexpr uint64 TYPE_FLOAT   = 11;
    static constexpr uint64 TYPE_DOUBLE  = 12;
    */

    // test create
    fields.insert(DBFields::TYPE_UINT64, 8, 1, "Student ID");
    fields.insert(DBFields::TYPE_CHAR, 100, 0, "Student name");
    fields.insert(DBFields::TYPE_BOOL, 1, 0, "Clever or Foolish");

    int rtv;
    // optimal on my os X 16KB
    // optimal on my Fedora 64KB
    rtv = table.create("student", fields, 1024 * 16);
    assert(rtv == 0);

    rtv = table.open("student");
    assert(rtv == 0);

    cout << "Table name: " << table._table_name << endl;
    cout << "Number of fields: " << table._num_fields << endl;
    cout << "Pages in each map page: " << table._pages_each_map_page << endl;
    cout << "Record length: " << table._record_length << endl;
    cout << "Number of records in each page: " << table._num_records_each_page << endl;
    cout << "Last empty slots map page: " << table._last_empty_slots_map_page << endl;
    cout << "Last record page: " << table._last_record_page << endl;

    cout << "Empty slots: " << table._empty_slots_map.size() << endl;
    for (int i = 0; i < table._empty_slots_map.size(); ++i) {
        if (table._empty_slots_map[i])
            cout << "    " << i << endl;
    }

    cout << "DBField info: " << endl;
    DBFields& fields2 = table._fields;
    cout << "Num fields: " << fields2.size() << endl;
    cout << "Total length: " << fields2.recordLength() << endl;

    for (int i = 0; i < fields2.size(); ++i)
        cout << fields2.field_id()[i] << ' ' << fields2.field_type()[i] << ' '
             << fields2.field_length()[i] << ' ' << fields2.primary_key()[i] << ' '
             << fields2.field_name()[i] << endl;

    unsigned long long student_id = 0x2001;
    char student_name[1000] = "John Idiot";
    bool clever = 1;

    /*
    // insert until the first map page is full
    for (int i = 0; i < 32573 * 37; ++i) {
        student_id += 1;
        clever ^= 1;
        rtv = table.insertRecord({ &student_id, student_name, &clever });
        assert(rtv == 0);
    }
    */

    // close table
    rtv = table.close();
    assert(rtv == 0);

    rtv = table.open("student");
    assert(rtv == 0);

    for (int i = 0; i < 149 + 3; ++i) {
        student_id += 1;
        clever ^= 1;
        rtv = table.insertRecord({ &student_id, student_name, &clever });
        assert(rtv == 0);
    }

    table.removeRecord({ 4, 32 });

    /*
    // test traverse function
    ofstream fout("traverse_result", fstream::out | fstream::binary);
    auto writeTofile = [&fout, &table](const char* record, const RID rid) {
        fout.write(record, table._record_length);
    };

    table.traverseRecords(writeTofile);
    */

    rtv = table.close();
    assert(rtv == 0);

    // test remove
    // rtv = table.remove("student");
    // cout << rtv << endl;

}
<commit_msg>add test for modifyRecord()<commit_after>/******************************************************************************
 *  Copyright (c) 2014 Jinming Hu
 *  Distributed under the MIT license
 *  (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT)
 *
 *  Project:
 *  Filename: db_tablemgr_test.cc
 *  Version: 1.0
 *  Author: Jinming Hu
 *  E-mail: hjm211324@gmail.com
 *  Date: Oct. 24, 2014
 *  Time: 09:44:22
 *  Description:
 *****************************************************************************/
#include <iostream>
#include <cassert>
#include "../src/db_tablemanager.h"
#include "../src/db_fields.h"

int main() {
    using namespace std;
    using namespace Database;

    DBTableManager table;

    DBFields fields;
    /*
    static constexpr uint64 TYPE_INT8    = 0;
    static constexpr uint64 TYPE_UINT8   = 1;
    static constexpr uint64 TYPE_INT16   = 2;
    static constexpr uint64 TYPE_UINT16  = 3;
    static constexpr uint64 TYPE_INT32   = 4;
    static constexpr uint64 TYPE_UINT32  = 5;
    static constexpr uint64 TYPE_INT64   = 6;
    static constexpr uint64 TYPE_UINT64  = 7;
    static constexpr uint64 TYPE_BOOL    = 8;
    static constexpr uint64 TYPE_CHAR    = 9;
    static constexpr uint64 TYPE_UCHAR   = 10;
    static constexpr uint64 TYPE_FLOAT   = 11;
    static constexpr uint64 TYPE_DOUBLE  = 12;
    */

    // test create
    fields.insert(DBFields::TYPE_UINT64, 8, 1, "Student ID");
    fields.insert(DBFields::TYPE_CHAR, 100, 0, "Student name");
    fields.insert(DBFields::TYPE_BOOL, 1, 0, "Clever or Foolish");

    int rtv;
    // optimal on my os X 16KB
    // optimal on my Fedora 64KB
    rtv = table.create("student", fields, 1024 * 16);
    assert(rtv == 0);

    rtv = table.open("student");
    assert(rtv == 0);

    cout << "Table name: " << table._table_name << endl;
    cout << "Number of fields: " << table._num_fields << endl;
    cout << "Pages in each map page: " << table._pages_each_map_page << endl;
    cout << "Record length: " << table._record_length << endl;
    cout << "Number of records in each page: " << table._num_records_each_page << endl;
    cout << "Last empty slots map page: " << table._last_empty_slots_map_page << endl;
    cout << "Last record page: " << table._last_record_page << endl;

    cout << "Empty slots: " << table._empty_slots_map.size() << endl;
    for (int i = 0; i < table._empty_slots_map.size(); ++i) {
        if (table._empty_slots_map[i])
            cout << "    " << i << endl;
    }

    cout << "DBField info: " << endl;
    DBFields& fields2 = table._fields;
    cout << "Num fields: " << fields2.size() << endl;
    cout << "Total length: " << fields2.recordLength() << endl;

    for (int i = 0; i < fields2.size(); ++i)
        cout << fields2.field_id()[i] << ' ' << fields2.field_type()[i] << ' '
             << fields2.field_length()[i] << ' ' << fields2.primary_key()[i] << ' '
             << fields2.field_name()[i] << endl;

    unsigned long long student_id = 0x2001;
    char student_name[1000] = "John Idiot";
    bool clever = 1;

    /*
    // insert until the first map page is full
    for (int i = 0; i < 32573 * 37; ++i) {
        student_id += 1;
        clever ^= 1;
        rtv = table.insertRecord({ &student_id, student_name, &clever });
        assert(rtv == 0);
    }
    */

    // close table
    rtv = table.close();
    assert(rtv == 0);

    rtv = table.open("student");
    assert(rtv == 0);

    for (int i = 0; i < 149 + 3; ++i) {
        student_id += 1;
        clever ^= 1;
        rtv = table.insertRecord({ &student_id, student_name, &clever });
        assert(rtv == 0);
    }

    table.removeRecord({ 4, 32 });

    table.modifyRecord({ 4, 1 }, 0, new int(0xffff));

    /*
    // test traverse function
    ofstream fout("traverse_result", fstream::out | fstream::binary);
    auto writeTofile = [&fout, &table](const char* record, const RID rid) {
        fout.write(record, table._record_length);
    };

    table.traverseRecords(writeTofile);
    */

    rtv = table.close();
    assert(rtv == 0);

    // test remove
    // rtv = table.remove("student");
    // cout << rtv << endl;

}
<|endoftext|>


<commit_before>#ifndef LM_HH
#define LM_HH

#include <float.h>
#include "misc/types.hh"
#include "FixedArray.hh"

namespace fsalm {

  class Semiring {
  public:
    Semiring() : one(0), zero(-1e30) { }
    virtual ~Semiring() { }
    virtual float plus(float a, float b) = 0;
    virtual float times(float a, float b) = 0;
    virtual float divide(float a, float b) = 0;
    virtual bool equal(float a, float b) = 0;
    float one;
    float zero;
  };

  class MaxPlusSemiring : public Semiring {
  public:
    virtual ~MaxPlusSemiring() { }
    virtual float plus(float a, float b) { return a < b ? b : a; }
    virtual float times(float a, float b) { return a + b; }
    virtual float divide(float a, float b) { return a - b; }
    virtual bool equal(float a, float b) { return a == b; }
  };

  /** Class for storing ngram language model in a fst format with
   * backoff arcs.
   *
   * INVARIANTS:
   *
   * - before trim() there may be nodes without children and bt=0
   *
   * - after trim() only final node has bt=0 and has zero children
   *
   * - node n has zero children if limit[n-1] == limit[n] or limit[n] == 0
   *
   * IMPLEMENTATION NOTES:
   *
   * - Backoff information is stored in the nodes instead of normal
   * arcs.  Otherwise, creating the arcs in proper order would be
   * troublesome from ARPA format.
   *
   * ASSUMES:
   * - children of a context are inserted in sorted chunk
   * - lower order is inserted before higher order
   */
  class LM {
  public:

    typedef FixedArray<int> Array;
    typedef FixedArray<float> FloatArray;

    Str start_str;
    Str end_str;
    Semiring *semiring;

    LM();
    void reset();
    const SymbolMap &symbol_map() const { return m_symbol_map; }
    int start_symbol() const { return m_start_symbol; }
    int end_symbol() const { return m_end_symbol; }
    int final_node_id() const { return m_final_node_id; }
    int empty_node_id() const { return m_empty_node_id; }
    int initial_node_id() const { return m_initial_node_id; }
    int order() const { return m_order; }
    int num_arcs() const { return m_arcs.symbol.num_elems(); }
    int num_nodes() const { return m_nodes.bo_target.num_elems(); }
    float final_score() const { return m_final_score; }

    /** Return the number of explicit children of node. */
    int num_children(int node_id) const;

    /** String describing a vector of symbol indices. */
    Str str(const IntVec &vec) const;

    /** Find context node for given backoff vector by backoffing
     * further if necessary.
     *
     * \note Throws exception if given ngram ends in sentence end
     * symbol.
     *
     * \param vec = candidate context for the backoff
     * \return node index corresponding to backoff context
     */
    int find_backoff(IntVec vec) const;

    /** Move to next node through given symbol but do not backoff.
     *
     * Finds the arc that starts from given node and has the given
     * symbol assigned, then returns its target node.
     *
     * \param node_id The node to start from (final node not allowed), or
     * empty_node_id() to search every node(?)
     * \param symbol The symbol to search for.
     * \param score Float pointer to which the possible score of the arc is ADDED
     * \return The resulting node (or -1 if explicit arc with symbol not found).
     */
    int walk_no_bo(int node_id, int symbol, float *score = NULL) const;

    /** Walks through a list of symbols but does not backoff.
     *
     * Finds a path that starts from given node and has the list of symbols
     * assigned in given order, then returns the target node of the last arc.
     *
     * \param node_id The node to start from (final node not allowed), or
     * empty_node_id() to search every node(?)
     * \param vec The list of symbols to traverse.
     * \param score Float pointer to which the possible score of the arc is ADDED
     * \return The resulting node (or -1 if explicit arc with symbol not found).
     */
    int walk_no_bo(int node_id, const IntVec &vec, float *score = NULL) const;

    /** Move to next node through given symbols without backoffing.
     * Same as above, but returns node indices for each symbol in a
     * vector. */
    IntVec walk_no_bo_vec(int node_id, const IntVec &vec,
                          float *score = NULL) const;

    /** Move to next node through given symbol by backoffing if necessary.
     *
     * \param node_id = the node to start from (final node not allowed)
     * \param symbol = the symbol to traverse through
     * \param score = float pointer to which the score is ADDED
     * \return the resulting node
     */
    int walk(int node_id, int symbol, float *score = NULL) const;
    int walk(int node_id, const IntVec &vec, float *score = NULL) const;

    void new_arc(int src_node_id, int symbol, int tgt_node_id, float score);
    void new_ngram(const IntVec &vec, float score, float bo_score);
    int new_node();
    void set_arc(int arc_id, int symbol, int target, float score);
    void trim();
    void quantize(int bits);

    /** Compute potential of each node (used by push). */
    void compute_potential(FloatVec &d);

    /** Push scores as early as possible. */
    void push();

    /** Reads the language model in ARPA format. */
    void read_arpa(FILE *file, bool show_progress = false);
    /** Reads the language model in a non-standard format. */
    void read(FILE *file);
    /** Writes the language model in a non-standard format. */
    void write(FILE *file) const;

    /** Write the language model in MIT fst format. */
    void write_fst(FILE *file, Str bo_symbol = "<B>") const;

    /** Write the language model in ATT fsmt format. */
    void write_fsmt(FILE *file, Str bo_symbol = "<B>") const;
    void write_fsmt_node(FILE *file, int n, Str bo_symbol) const;

    /** Fetch probabilities for all symbols (ignoring non-events). */
    void fetch_probs(int node_id, FloatVec &vec);

    Str debug_str() const;
    bool debug_check_sum(int node_id) const;
    bool debug_check_sums() const;
    bool debug_check_zero_bo() const;

  private:

    /** Incoming arc used temporarily by compute_potential() */
    struct InArc {
      InArc() : source(-1), arc_id(-1) { }
      InArc(int source, int arc_id) : source(source), arc_id(arc_id) { }
      int source;
      int arc_id;
    };

    /** Node information */
    struct {
      FloatArray bo_score;
      Array bo_target;
      Array limit_arc;  //!< Index to one past the last arc that starts from this node.
    } m_nodes;

    /** Arc information */
    struct {
      Array symbol;  //!< The symbol assigned to the arc.
      Array target;  //!< The target node.
      FloatArray score;  //!< Possible score of the arc.
    } m_arcs;

    /** Cache containing information about the last ngram inserted in
     * the strucure. */
    struct {
      IntVec ctx_vec;  //!< Context vector, i.e. all but the last symbol.
      int ctx_node_id;
    } m_cache;

    /** Mapping between language model symbols and indices. */
    SymbolMap m_symbol_map;

    /** Bit array defining non-event symbols. */
    BoolVec m_non_event;

    int m_order;
    int m_empty_node_id;
    int m_initial_node_id;
    int m_final_node_id;
    int m_start_symbol;
    int m_end_symbol;
    float m_final_score;
  };

};

#endif /* LM_HH */
<commit_msg>Added some Doxygen comments.<commit_after>#ifndef LM_HH
#define LM_HH

#include <float.h>
#include "misc/types.hh"
#include "FixedArray.hh"

namespace fsalm {

  class Semiring {
  public:
    Semiring() : one(0), zero(-1e30) { }
    virtual ~Semiring() { }
    virtual float plus(float a, float b) = 0;
    virtual float times(float a, float b) = 0;
    virtual float divide(float a, float b) = 0;
    virtual bool equal(float a, float b) = 0;
    float one;
    float zero;
  };

  class MaxPlusSemiring : public Semiring {
  public:
    virtual ~MaxPlusSemiring() { }
    virtual float plus(float a, float b) { return a < b ? b : a; }
    virtual float times(float a, float b) { return a + b; }
    virtual float divide(float a, float b) { return a - b; }
    virtual bool equal(float a, float b) { return a == b; }
  };

  /** Class for storing ngram language model in a fst format with
   * backoff arcs.
   *
   * INVARIANTS:
   *
   * - before trim() there may be nodes without children and bt=0
   *
   * - after trim() only final node has bt=0 and has zero children
   *
   * - node n has zero children if limit[n-1] == limit[n] or limit[n] == 0
   *
   * IMPLEMENTATION NOTES:
   *
   * - Backoff information is stored in the nodes instead of normal
   * arcs.  Otherwise, creating the arcs in proper order would be
   * troublesome from ARPA format.
   *
   * ASSUMES:
   * - children of a context are inserted in sorted chunk
   * - lower order is inserted before higher order
   */
  class LM {
  public:

    typedef FixedArray<int> Array;
    typedef FixedArray<float> FloatArray;

    Str start_str;
    Str end_str;
    Semiring *semiring;

    LM();
    void reset();
    const SymbolMap &symbol_map() const { return m_symbol_map; }
    int start_symbol() const { return m_start_symbol; }
    int end_symbol() const { return m_end_symbol; }
    int final_node_id() const { return m_final_node_id; }
    int empty_node_id() const { return m_empty_node_id; }
    int initial_node_id() const { return m_initial_node_id; }
    int order() const { return m_order; }
    int num_arcs() const { return m_arcs.symbol.num_elems(); }
    int num_nodes() const { return m_nodes.bo_target.num_elems(); }
    float final_score() const { return m_final_score; }

    /** Return the number of explicit children of node. */
    int num_children(int node_id) const;

    /** String describing a vector of symbol indices. */
    Str str(const IntVec &vec) const;

    /** Find context node for given backoff vector by backoffing
     * further if necessary.
     *
     * \note Throws exception if given ngram ends in sentence end
     * symbol.
     *
     * \param vec = candidate context for the backoff
     * \return node index corresponding to backoff context
     */
    int find_backoff(IntVec vec) const;

    /** Move to next node through given symbol but do not backoff.
     *
     * Finds the arc that starts from given node and has the given
     * symbol assigned, then returns its target node.
     *
     * \param node_id The node to start from (final node not allowed), or
     * empty_node_id() to search every node(?)
     * \param symbol The symbol to search for.
     * \param score Float pointer to which the possible score of the arc is ADDED
     * \return The resulting node (or -1 if explicit arc with symbol not found).
     */
    int walk_no_bo(int node_id, int symbol, float *score = NULL) const;

    /** Walks through a list of symbols but does not backoff. Returns the index
     * of the resulting node.
     *
     * Finds a path that starts from given node and has the list of symbols
     * assigned in given order, then returns the target node of the last arc.
     *
     * \param node_id The node to start from (final node not allowed), or
     * empty_node_id() to search every node(?)
     * \param vec The list of symbols to traverse.
     * \param score Float pointer to which the possible score of the arc is ADDED
     * \return The resulting node (or -1 if explicit arc with symbol not found).
     */
    int walk_no_bo(int node_id, const IntVec &vec, float *score = NULL) const;

    /** Walks through a list of symbols but does not backoff. Returns indices of
     * all the traversed nodes.
     *
     * Finds a path that starts from given node and has the list of symbols
     * assigned in given order, then returns the target node of the last arc.
     *
     * \param node_id The node to start from (final node not allowed), or
     * empty_node_id() to search every node(?)
     * \param vec The list of symbols to traverse.
     * \param score Float pointer to which the possible score of the arc is ADDED
     * \return Indices of all the traversed nodes.
     */
    IntVec walk_no_bo_vec(int node_id, const IntVec &vec,
                          float *score = NULL) const;

    /** Move to next node through given symbol by backoffing if necessary.
     *
     * \param node_id = the node to start from (final node not allowed)
     * \param symbol = the symbol to traverse through
     * \param score = float pointer to which the score is ADDED
     * \return the resulting node
     */
    int walk(int node_id, int symbol, float *score = NULL) const;
    int walk(int node_id, const IntVec &vec, float *score = NULL) const;

    void new_arc(int src_node_id, int symbol, int tgt_node_id, float score);
    void new_ngram(const IntVec &vec, float score, float bo_score);
    int new_node();
    void set_arc(int arc_id, int symbol, int target, float score);
    void trim();
    void quantize(int bits);

    /** Compute potential of each node (used by push). */
    void compute_potential(FloatVec &d);

    /** Push scores as early as possible. */
    void push();

    /** Reads the language model in ARPA format. */
    void read_arpa(FILE *file, bool show_progress = false);
    /** Reads the language model in a non-standard format. */
    void read(FILE *file);
    /** Writes the language model in a non-standard format. */
    void write(FILE *file) const;

    /** Write the language model in MIT fst format. */
    void write_fst(FILE *file, Str bo_symbol = "<B>") const;

    /** Write the language model in ATT fsmt format. */
    void write_fsmt(FILE *file, Str bo_symbol = "<B>") const;
    void write_fsmt_node(FILE *file, int n, Str bo_symbol) const;

    /** Fetch probabilities for all symbols (ignoring non-events). */
    void fetch_probs(int node_id, FloatVec &vec);

    Str debug_str() const;
    bool debug_check_sum(int node_id) const;
    bool debug_check_sums() const;
    bool debug_check_zero_bo() const;

  private:

    /** Incoming arc used temporarily by compute_potential() */
    struct InArc {
      InArc() : source(-1), arc_id(-1) { }
      InArc(int source, int arc_id) : source(source), arc_id(arc_id) { }
      int source;
      int arc_id;
    };

    /** Node information */
    struct {
      FloatArray bo_score;
      Array bo_target;
      Array limit_arc;  //!< Index to one past the last arc that starts from this node.
    } m_nodes;

    /** Arc information */
    struct {
      Array symbol;  //!< The symbol assigned to the arc.
      Array target;  //!< The target node.
      FloatArray score;  //!< Possible score of the arc.
    } m_arcs;

    /** Cache containing information about the last ngram inserted in
     * the strucure. */
    struct {
      IntVec ctx_vec;  //!< Context vector, i.e. all but the last symbol.
      int ctx_node_id;
    } m_cache;

    /** Mapping between language model symbols and indices. */
    SymbolMap m_symbol_map;

    /** Bit array defining non-event symbols. */
    BoolVec m_non_event;

    int m_order;
    int m_empty_node_id;
    int m_initial_node_id;
    int m_final_node_id;
    int m_start_symbol;
    int m_end_symbol;
    float m_final_score;
  };

};

#endif /* LM_HH */
<|endoftext|>


<commit_before>#include "debugger.h"
extern "C" {
#include "reverse_aska.h"
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtkmm.h>

class ControlWidget : public Gtk::HBox
{
	Gtk::Button button_continue_pause;
	Gtk::Button button_stepover;
public:
	ControlWidget() :
		button_continue_pause("Continue / Pause"),
		button_stepover("Stepover")
	{
		pack_start(button_continue_pause, Gtk::PACK_SHRINK);
		pack_start(button_stepover, Gtk::PACK_SHRINK);
	}
};

class RegistersWidget : public Gtk::VBox
{
	Gtk::Label label;
	Gtk::ScrolledWindow scrwin;
	Gtk::TreeView treeview;
	Gtk::TreeModelColumn<Glib::ustring> name;
	Gtk::TreeModelColumn<int> value;
	Gtk::TreeModelColumn<Glib::ustring> type;
	Gtk::TreeModel::ColumnRecord record;
	Glib::RefPtr<Gtk::ListStore> liststore;
	const OsecpuDebugger& debugger;
public:
	RegistersWidget(const OsecpuDebugger& debugger) :
		label("Registers", Gtk::ALIGN_START, Gtk::ALIGN_LEFT),
		debugger(debugger)
	{
		pack_start(label, Gtk::PACK_SHRINK);
		scrwin.add(treeview);
		pack_start(scrwin);

		record.add(name);
		record.add(value);
		record.add(type);
		liststore = Gtk::ListStore::create(record);
		treeview.set_model(liststore);
		treeview.append_column("Name", name);
		treeview.append_column("Value", value);
		treeview.append_column("Type", type);
	}

	int Reload()
	{
		Gtk::TreeModel::Row row;
		int i;

		liststore->clear();

		for (i = 0; i < 0x40; i++) {
			char regname_c[4];
			Glib::ustring regname;
			Glib::ustring type_name("-");

			snprintf(regname_c, 4, "R%02X", i);
			regname = regname_c;

			row = *liststore->append();
			row[name] = regname;
			row[value] = debugger.osecpu->registers[i];
			row[type] = type_name;
		}

		for (i = 0; i < 0x40; i++) {
			char regname_c[4];
			char type_name_c[16];
			Glib::ustring regname;
			Glib::ustring type_name;

			snprintf(regname_c, 4, "P%02X", i);
			regname = regname_c;

			snprintf(type_name_c, 16, "%d", debugger.osecpu->pregisters[i].type);
			type_name = type_name_c;

			row = *liststore->append();
			row[name] = regname;
			row[value] = debugger.osecpu->pregisters[i].p.code;
			row[type] = type_name;
		}

		for (i = 0; i < 4; i++) {
			char regname_c[4];
			char type_name_c[16];
			Glib::ustring regname;
			Glib::ustring type_name("-");

			snprintf(regname_c, 4, "D%02X", i);
			regname = regname_c;

			row = *liststore->append();
			row[name] = regname;
			row[value] = debugger.osecpu->dregisters[i];
			row[type] = type_name;
		}

		return 1;
	}
};

class LabelsWidget : public Gtk::VBox
{
	Gtk::Label label;
	Gtk::ScrolledWindow scrwin;
	Gtk::TreeView treeview;
	Gtk::TreeModelColumn<int> number;
	Gtk::TreeModelColumn<int> codepos;
	Gtk::TreeModelColumn<Glib::ustring> type;
	Gtk::TreeModel::ColumnRecord record;
	Glib::RefPtr<Gtk::ListStore> liststore;
	const OsecpuDebugger& debugger;
public:
	LabelsWidget(const OsecpuDebugger& debugger) :
		label("Labels", Gtk::ALIGN_START, Gtk::ALIGN_LEFT),
		debugger(debugger)
	{
		pack_start(label, Gtk::PACK_SHRINK);
		scrwin.add(treeview);
		pack_start(scrwin);

		record.add(number);
		record.add(codepos);
		record.add(type);
		liststore = Gtk::ListStore::create(record);
		treeview.set_model(liststore);
		treeview.append_column("#", number);
		treeview.append_column("Pos", codepos);
		treeview.append_column("Type / Length", type);
	}

	int Reload()
	{
		Gtk::TreeModel::Row row;
		int i;

		liststore->clear();

		for (i = 0; i < debugger.osecpu->labelcnt; i++) {
			Glib::ustring type_name;

			if (debugger.osecpu->labels[i].data) {
				char type_name_c[32];
				snprintf(type_name_c, 32, "data (T_UINT8) (%dbytes)", debugger.osecpu->labels[i].datalen);
				type_name = type_name_c;
			} else {
				type_name = "code";
			}

			row = *liststore->append();
			row[number] = debugger.osecpu->labels[i].id;
			row[codepos] = debugger.osecpu->labels[i].pos;
			row[type] = type_name;
		}

		return 1;
	}
};

class CodeWidget : public Gtk::VBox
{
	Gtk::Label label;
	Gtk::ScrolledWindow scrwin;
	Gtk::TreeView treeview;
	Gtk::TreeModelColumn<int> inst_number;
	Gtk::TreeModelColumn<Glib::ustring> inst_string;
	Gtk::TreeModel::ColumnRecord record;
	Glib::RefPtr<Gtk::ListStore> liststore;
	const OsecpuDebugger& debugger;
public:
	CodeWidget(const OsecpuDebugger& debugger) :
		label("Code", Gtk::ALIGN_START, Gtk::ALIGN_LEFT),
		debugger(debugger)
	{
		pack_start(label, Gtk::PACK_SHRINK);
		scrwin.add(treeview);
		pack_start(scrwin);

		record.add(inst_number);
		record.add(inst_string);
		liststore = Gtk::ListStore::create(record);
		treeview.set_model(liststore);
		treeview.append_column("Instruction #", inst_number);
		treeview.append_column("ASKA", inst_string);
	}

	int Reload()
	{
		ReverseAska* raska;
		Gtk::TreeModel::Row row;
		int i;

		liststore->clear();

		raska = reverse_aska_init(debugger.osecpu->orig_code, debugger.osecpu->orig_codelen);
		if (!raska) return 0;

		for (i = 0; i < raska->idxcnt; i++) {
			// FIXME: inst, inst->inst_str are leaked memory
			struct ReverseAskaInstruction* inst;
			inst = get_instruction_string(raska, i);
			row = *liststore->append();
			row[inst_number] = i;
			row[inst_string] = inst->inst_str;
		}

		reverse_aska_free(raska);

		return 1;
	}
};

class DebuggerWindow : public Gtk::Window
{
	Gtk::VBox vbox, vbox_left, vbox_right;
	Gtk::HBox hbox;
	ControlWidget widget_control;
	RegistersWidget widget_registers;
	LabelsWidget widget_labels;
	CodeWidget widget_code;
	const OsecpuDebugger& debugger;
public:
	DebuggerWindow(const OsecpuDebugger& debugger) :
		debugger(debugger),
		widget_registers(debugger),
		widget_labels(debugger),
		widget_code(debugger)
	{
		resize(800, 500);
		set_title("OSECPU Debugger");
		vbox_left.pack_start(widget_control, Gtk::PACK_SHRINK);
		vbox_left.pack_start(widget_registers);
		vbox_left.pack_start(widget_labels);
		vbox_left.set_size_request(300);
		vbox_right.pack_start(widget_code);
		hbox.pack_start(vbox_left, Gtk::PACK_SHRINK);
		hbox.pack_start(vbox_right);
		vbox.pack_start(hbox);
		add(vbox);
		show_all_children();

		Reload();
	}

	void Reload() {
		widget_registers.Reload();
		widget_labels.Reload();
		widget_code.Reload();
	}
};

void* create_debugger_window_thread(void* data)
{
	OsecpuDebugger* debugger = (OsecpuDebugger*)data;
	Gtk::Main gtk(NULL, NULL);
	debugger->window = new DebuggerWindow(*debugger);
	Gtk::Main::run(*(DebuggerWindow*)debugger->window);
	debugger->window = NULL;
}

extern "C" OsecpuDebugger* debugger_init(struct Osecpu* osecpu)
{
	OsecpuDebugger* debugger;
	debugger = (OsecpuDebugger*)malloc(sizeof(OsecpuDebugger));
	if (!debugger) return NULL;
	memset(debugger, 0, sizeof(OsecpuDebugger));
	debugger->osecpu = osecpu;

	return debugger;
}

extern "C" void debugger_free(OsecpuDebugger* debugger)
{
	free(debugger);
}

extern "C" void debugger_open(OsecpuDebugger* debugger)
{
	char cmdbuf[1024];

	if (!debugger->window) {
		pthread_create(&debugger->windowThread, NULL, create_debugger_window_thread, debugger);
		while (!debugger->window);
	}

	while (1) {
		printf("debug> ");
		fgets(cmdbuf, 1024, stdin);
		cmdbuf[strlen(cmdbuf)-1] = 0;
		if (strcmp(cmdbuf, "continue") == 0) {
			if (continue_osecpu(debugger->osecpu) == 2) {
				printf("breakpoint.\n");
				debugger_open(debugger);
			}
			return;
		} else if (strcmp(cmdbuf, "next") == 0) {
			do_next_instruction(debugger->osecpu);
			if (debugger->osecpu->pregisters[0x3f].p.code >= debugger->osecpu->codelen) {
				return;
			}
		} else if (strcmp(cmdbuf, "coredump") == 0) {
			coredump(debugger->osecpu);
		} else {
			printf("command: continue, next, coredump\n");
		}
	}
}

<commit_msg>ControlWidget signals<commit_after>#include "debugger.h"
extern "C" {
#include "reverse_aska.h"
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtkmm.h>

class ControlWidget : public Gtk::HBox
{
	Gtk::Button button_continue_pause;
	Gtk::Button button_stepover;
public:
	ControlWidget() :
		button_continue_pause("Continue / Pause"),
		button_stepover("Stepover")
	{
		pack_start(button_continue_pause, Gtk::PACK_SHRINK);
		pack_start(button_stepover, Gtk::PACK_SHRINK);

		button_continue_pause.signal_clicked().connect(sigc::mem_fun(this, &ControlWidget::on_continue_pause_button_clicked));
		button_stepover.signal_clicked().connect(sigc::mem_fun(this, &ControlWidget::on_stepover_button_clicked));
	}

	void on_continue_pause_button_clicked()
	{
	}

	void on_stepover_button_clicked()
	{
	}
};

class RegistersWidget : public Gtk::VBox
{
	Gtk::Label label;
	Gtk::ScrolledWindow scrwin;
	Gtk::TreeView treeview;
	Gtk::TreeModelColumn<Glib::ustring> name;
	Gtk::TreeModelColumn<int> value;
	Gtk::TreeModelColumn<Glib::ustring> type;
	Gtk::TreeModel::ColumnRecord record;
	Glib::RefPtr<Gtk::ListStore> liststore;
	const OsecpuDebugger& debugger;
public:
	RegistersWidget(const OsecpuDebugger& debugger) :
		label("Registers", Gtk::ALIGN_START, Gtk::ALIGN_LEFT),
		debugger(debugger)
	{
		pack_start(label, Gtk::PACK_SHRINK);
		scrwin.add(treeview);
		pack_start(scrwin);

		record.add(name);
		record.add(value);
		record.add(type);
		liststore = Gtk::ListStore::create(record);
		treeview.set_model(liststore);
		treeview.append_column("Name", name);
		treeview.append_column("Value", value);
		treeview.append_column("Type", type);
	}

	int Reload()
	{
		Gtk::TreeModel::Row row;
		int i;

		liststore->clear();

		for (i = 0; i < 0x40; i++) {
			char regname_c[4];
			Glib::ustring regname;
			Glib::ustring type_name("-");

			snprintf(regname_c, 4, "R%02X", i);
			regname = regname_c;

			row = *liststore->append();
			row[name] = regname;
			row[value] = debugger.osecpu->registers[i];
			row[type] = type_name;
		}

		for (i = 0; i < 0x40; i++) {
			char regname_c[4];
			char type_name_c[16];
			Glib::ustring regname;
			Glib::ustring type_name;

			snprintf(regname_c, 4, "P%02X", i);
			regname = regname_c;

			snprintf(type_name_c, 16, "%d", debugger.osecpu->pregisters[i].type);
			type_name = type_name_c;

			row = *liststore->append();
			row[name] = regname;
			row[value] = debugger.osecpu->pregisters[i].p.code;
			row[type] = type_name;
		}

		for (i = 0; i < 4; i++) {
			char regname_c[4];
			char type_name_c[16];
			Glib::ustring regname;
			Glib::ustring type_name("-");

			snprintf(regname_c, 4, "D%02X", i);
			regname = regname_c;

			row = *liststore->append();
			row[name] = regname;
			row[value] = debugger.osecpu->dregisters[i];
			row[type] = type_name;
		}

		return 1;
	}
};

class LabelsWidget : public Gtk::VBox
{
	Gtk::Label label;
	Gtk::ScrolledWindow scrwin;
	Gtk::TreeView treeview;
	Gtk::TreeModelColumn<int> number;
	Gtk::TreeModelColumn<int> codepos;
	Gtk::TreeModelColumn<Glib::ustring> type;
	Gtk::TreeModel::ColumnRecord record;
	Glib::RefPtr<Gtk::ListStore> liststore;
	const OsecpuDebugger& debugger;
public:
	LabelsWidget(const OsecpuDebugger& debugger) :
		label("Labels", Gtk::ALIGN_START, Gtk::ALIGN_LEFT),
		debugger(debugger)
	{
		pack_start(label, Gtk::PACK_SHRINK);
		scrwin.add(treeview);
		pack_start(scrwin);

		record.add(number);
		record.add(codepos);
		record.add(type);
		liststore = Gtk::ListStore::create(record);
		treeview.set_model(liststore);
		treeview.append_column("#", number);
		treeview.append_column("Pos", codepos);
		treeview.append_column("Type / Length", type);
	}

	int Reload()
	{
		Gtk::TreeModel::Row row;
		int i;

		liststore->clear();

		for (i = 0; i < debugger.osecpu->labelcnt; i++) {
			Glib::ustring type_name;

			if (debugger.osecpu->labels[i].data) {
				char type_name_c[32];
				snprintf(type_name_c, 32, "data (T_UINT8) (%dbytes)", debugger.osecpu->labels[i].datalen);
				type_name = type_name_c;
			} else {
				type_name = "code";
			}

			row = *liststore->append();
			row[number] = debugger.osecpu->labels[i].id;
			row[codepos] = debugger.osecpu->labels[i].pos;
			row[type] = type_name;
		}

		return 1;
	}
};

class CodeWidget : public Gtk::VBox
{
	Gtk::Label label;
	Gtk::ScrolledWindow scrwin;
	Gtk::TreeView treeview;
	Gtk::TreeModelColumn<int> inst_number;
	Gtk::TreeModelColumn<Glib::ustring> inst_string;
	Gtk::TreeModel::ColumnRecord record;
	Glib::RefPtr<Gtk::ListStore> liststore;
	const OsecpuDebugger& debugger;
public:
	CodeWidget(const OsecpuDebugger& debugger) :
		label("Code", Gtk::ALIGN_START, Gtk::ALIGN_LEFT),
		debugger(debugger)
	{
		pack_start(label, Gtk::PACK_SHRINK);
		scrwin.add(treeview);
		pack_start(scrwin);

		record.add(inst_number);
		record.add(inst_string);
		liststore = Gtk::ListStore::create(record);
		treeview.set_model(liststore);
		treeview.append_column("Instruction #", inst_number);
		treeview.append_column("ASKA", inst_string);
	}

	int Reload()
	{
		ReverseAska* raska;
		Gtk::TreeModel::Row row;
		int i;

		liststore->clear();

		raska = reverse_aska_init(debugger.osecpu->orig_code, debugger.osecpu->orig_codelen);
		if (!raska) return 0;

		for (i = 0; i < raska->idxcnt; i++) {
			// FIXME: inst, inst->inst_str are leaked memory
			struct ReverseAskaInstruction* inst;
			inst = get_instruction_string(raska, i);
			row = *liststore->append();
			row[inst_number] = i;
			row[inst_string] = inst->inst_str;
		}

		reverse_aska_free(raska);

		return 1;
	}
};

class DebuggerWindow : public Gtk::Window
{
	Gtk::VBox vbox, vbox_left, vbox_right;
	Gtk::HBox hbox;
	ControlWidget widget_control;
	RegistersWidget widget_registers;
	LabelsWidget widget_labels;
	CodeWidget widget_code;
	const OsecpuDebugger& debugger;
public:
	DebuggerWindow(const OsecpuDebugger& debugger) :
		debugger(debugger),
		widget_registers(debugger),
		widget_labels(debugger),
		widget_code(debugger)
	{
		resize(800, 500);
		set_title("OSECPU Debugger");
		vbox_left.pack_start(widget_control, Gtk::PACK_SHRINK);
		vbox_left.pack_start(widget_registers);
		vbox_left.pack_start(widget_labels);
		vbox_left.set_size_request(300);
		vbox_right.pack_start(widget_code);
		hbox.pack_start(vbox_left, Gtk::PACK_SHRINK);
		hbox.pack_start(vbox_right);
		vbox.pack_start(hbox);
		add(vbox);
		show_all_children();

		Reload();
	}

	void Reload() {
		widget_registers.Reload();
		widget_labels.Reload();
		widget_code.Reload();
	}
};

void* create_debugger_window_thread(void* data)
{
	OsecpuDebugger* debugger = (OsecpuDebugger*)data;
	Gtk::Main gtk(NULL, NULL);
	debugger->window = new DebuggerWindow(*debugger);
	Gtk::Main::run(*(DebuggerWindow*)debugger->window);
	debugger->window = NULL;
}

extern "C" OsecpuDebugger* debugger_init(struct Osecpu* osecpu)
{
	OsecpuDebugger* debugger;
	debugger = (OsecpuDebugger*)malloc(sizeof(OsecpuDebugger));
	if (!debugger) return NULL;
	memset(debugger, 0, sizeof(OsecpuDebugger));
	debugger->osecpu = osecpu;

	return debugger;
}

extern "C" void debugger_free(OsecpuDebugger* debugger)
{
	free(debugger);
}

extern "C" void debugger_open(OsecpuDebugger* debugger)
{
	char cmdbuf[1024];

	if (!debugger->window) {
		pthread_create(&debugger->windowThread, NULL, create_debugger_window_thread, debugger);
		while (!debugger->window);
	}

	while (1) {
		printf("debug> ");
		fgets(cmdbuf, 1024, stdin);
		cmdbuf[strlen(cmdbuf)-1] = 0;
		if (strcmp(cmdbuf, "continue") == 0) {
			if (continue_osecpu(debugger->osecpu) == 2) {
				printf("breakpoint.\n");
				debugger_open(debugger);
			}
			return;
		} else if (strcmp(cmdbuf, "next") == 0) {
			do_next_instruction(debugger->osecpu);
			if (debugger->osecpu->pregisters[0x3f].p.code >= debugger->osecpu->codelen) {
				return;
			}
		} else if (strcmp(cmdbuf, "coredump") == 0) {
			coredump(debugger->osecpu);
		} else {
			printf("command: continue, next, coredump\n");
		}
	}
}

<|endoftext|>


<commit_before>#include "handler.hpp"

namespace dafs
{
    void
    HandleCreateFile(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        // dafs::FileInfo info
    }

    void
    HandleDeleteFile(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        // dafs::FileInfo info
    }

    void
    HandleOpenFile(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        // dafs::FileInfo info
    }

    void
    HandleReadFile(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        // dafs::FileInfo info
    }

    void
    HandleWriteFile(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        // dafs::Bytes bytes
        // dafs::FileInfo info
    }

    void
    HandleReadBlock(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        // dafs::BlockInfo info
    }

    void
    HandleWriteBlock(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        // dafs::Bytes bytes
        // dafs::BlockInfo info
    }

    void HandleAllocate(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        // dafs::Allocation allocation
    }

    void HandleAllocated(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        // dafs::Allocation allocation
    }
}
<commit_msg>Add handler implementations<commit_after>#include "handler.hpp"

namespace dafs
{
    void
    HandleCreateFile(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        auto fileinfo = metadata.GetValue<dafs::FileInfo>(dafs::FileInfoKey);
        store.CreateFile(*fileinfo);
    }

    void
    HandleDeleteFile(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        auto fileinfo = metadata.GetValue<dafs::FileInfo>(dafs::FileInfoKey);
        store.DeleteFile(*fileinfo);
    }

    void
    HandleOpenFile(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        // dafs::FileInfo info
    }

    void
    HandleReadFile(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        auto fileinfo = metadata.GetValue<dafs::FileInfo>(dafs::FileInfoKey);
        store.ReadFile(*fileinfo);
    }

    void
    HandleWriteFile(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        // dafs::Bytes bytes
        // dafs::FileInfo info
    }

    void
    HandleReadBlock(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        auto blockinfo = metadata.GetValue<dafs::BlockInfo>(dafs::BlockInfoKey);
        store.ReadBlock(*blockinfo);
    }

    void
    HandleWriteBlock(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        // dafs::Bytes bytes
        // dafs::BlockInfo info
    }

    void HandleAllocate(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        // dafs::Allocation allocation
    }

    void HandleAllocated(
        dafs::Storage store,
        dafs::MetaDataParser metadata,
        dafs::Sender& sender)
    {
        // dafs::Allocation allocation
    }
}
<|endoftext|>


<commit_before>#include "all_defines.hpp"
#include "history.hpp"
#include "processes.hpp"
#include "bytecodes.hpp"
#include "reader.hpp"
#include "types.hpp"

void History::entry(void) {
	if(known_type<Closure>(stack[0])->kontinuation) {
		/*called a continuation: remove tail calls using this continuation*/
		known_type<Closure>(stack[0])->kontinuation->clear();
	} else {
		/*called an ordinary function: add to tail calls on current continuation*/
		if(stack.size() < 2) return;

		Closure* pkclos = maybe_type<Closure>(stack[1]);
		if(!pkclos) return;

		Closure& kclos = *pkclos;
		if(!kclos.kontinuation) return;

		InnerRing& inner_ring = *kclos.kontinuation;
		inner_ring.push_front(Item());
		// ?? for some reason, after insertion capacity must be set again
		inner_ring.repeat_set_capacity();

		Item& it = inner_ring.front();
		it.resize(stack.size() - 1);
		it[0] = stack[0];
		/*skip stack[1] in the debug dump*/
		for(size_t i = 1; i < stack.size(); ++i) {
			it[i] = stack[i + 1];
		}
	}
}

// returned list is of type
// ((functon arg1 ... argn) ...)
void History::to_list(Process & proc) {
	ProcessStack & s = proc.stack;
	size_t count = 0; // number of elements in the history
	Object::ref i = stack[1];
	Closure* pkclos;
	pkclos = maybe_type<Closure>(i);
	if(!pkclos) goto end_outer_loop;
	if(!pkclos->kontinuation) goto end_outer_loop;
outer_loop:
	/*go through the kontinuation*/
	{ InnerRing& ring = *pkclos->kontinuation;
		for(InnerRing::iterator it = ring.begin();
				it != ring.end();
				++it) {
			Item& item = *it;
			{ size_t count = 0;
				for(Item::iterator it = item.begin();
						it != item.end();
						++it) {
					proc.stack.push(*it);
					++count;
				}
				proc.stack.push(Object::nil());
				for(; count; --count) {
					bytecode_cons(proc, stack);
				}
			}
			++count;
		}
	}
	/*search for a parent continuation*/
	for(size_t i = 0; i < pkclos->size(); ++i) {
		Closure* npkclos = maybe_type<Closure>((*pkclos)[i]);
		if(npkclos) {
			if(npkclos->kontinuation) {
				pkclos = npkclos;
				goto outer_loop;
			}
		}
	}
end_outer_loop:
	proc.stack.push(Object::nil());
	// build the list
	for (; count; --count) {
		bytecode_cons(proc, proc.stack);
	}
}

void History::InnerRing::traverse_references(GenericTraverser* gt) {
	for(iterator it = begin(); it != end(); ++it) {
		for(Item::iterator vit = it->begin(); vit != it->end(); ++vit) {
			gt->traverse(*vit);
		}
	}
}

<commit_msg>src/history.cpp: Also check stack[0] if it's a continuation<commit_after>#include "all_defines.hpp"
#include "history.hpp"
#include "processes.hpp"
#include "bytecodes.hpp"
#include "reader.hpp"
#include "types.hpp"

void History::entry(void) {
	if(known_type<Closure>(stack[0])->kontinuation) {
		/*called a continuation: remove tail calls using this continuation*/
		known_type<Closure>(stack[0])->kontinuation->clear();
	} else {
		/*called an ordinary function: add to tail calls on current continuation*/
		if(stack.size() < 2) return;

		Closure* pkclos = maybe_type<Closure>(stack[1]);
		if(!pkclos) return;

		Closure& kclos = *pkclos;
		if(!kclos.kontinuation) return;

		InnerRing& inner_ring = *kclos.kontinuation;
		inner_ring.push_front(Item());
		// ?? for some reason, after insertion capacity must be set again
		inner_ring.repeat_set_capacity();

		Item& it = inner_ring.front();
		it.resize(stack.size() - 1);
		it[0] = stack[0];
		/*skip stack[1] in the debug dump*/
		for(size_t i = 1; i < stack.size(); ++i) {
			it[i] = stack[i + 1];
		}
	}
}

// returned list is of type
// ((functon arg1 ... argn) ...)
void History::to_list(Process & proc) {
	ProcessStack & s = proc.stack;
	size_t count = 0; // number of elements in the history
	Closure* pkclos;
	pkclos = maybe_type<Closure>(stack[1]);
	if(pkclos && pkclos->kontinuation) goto outer_loop;
	pkclos = maybe_type<Closure>(stack[0]);
	if(pkclos && pkclos->kontinuation) goto outer_loop;
	goto end_outer_loop;
outer_loop:
	/*go through the kontinuation*/
	{ InnerRing& ring = *pkclos->kontinuation;
		for(InnerRing::iterator it = ring.begin();
				it != ring.end();
				++it) {
			Item& item = *it;
			{ size_t count = 0;
				for(Item::iterator it = item.begin();
						it != item.end();
						++it) {
					proc.stack.push(*it);
					++count;
				}
				proc.stack.push(Object::nil());
				for(; count; --count) {
					bytecode_cons(proc, stack);
				}
			}
			++count;
		}
	}
	/*search for a parent continuation*/
	for(size_t i = 0; i < pkclos->size(); ++i) {
		Closure* npkclos = maybe_type<Closure>((*pkclos)[i]);
		if(npkclos) {
			if(npkclos->kontinuation) {
				pkclos = npkclos;
				goto outer_loop;
			}
		}
	}
end_outer_loop:
	proc.stack.push(Object::nil());
	// build the list
	for (; count; --count) {
		bytecode_cons(proc, proc.stack);
	}
}

void History::InnerRing::traverse_references(GenericTraverser* gt) {
	for(iterator it = begin(); it != end(); ++it) {
		for(Item::iterator vit = it->begin(); vit != it->end(); ++vit) {
			gt->traverse(*vit);
		}
	}
}

<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include "Lex.h"
#include "JZFileUtil.h"

TEST(LexUtil, eraseLineSeperator){
  StringList fileList = JZGetAllFiles("./test/Samples/LexUtilEraseLineSeperator", false);
  for(auto i = fileList.begin(); i < fileList.end(); i++)
  {
    uint64 buffSize = 0;
    unsigned char* buff = JZGetFileData(i->c_str(),&buffSize);
    const char* eraseRet = LexUtil::eraseLineSeperator((const char*)buff, &buffSize);
  }
}
<commit_msg>get a bug<commit_after>#include <gtest/gtest.h>
#include "Lex.h"
#include "JZFileUtil.h"
#include <string.h>

TEST(LexUtil, eraseLineSeperator){
  const char* input1 = "123456\\ \n 12345";
  uint64 bufSize1 = strlen(input1);
  const char* eraseRet1 = LexUtil::eraseLineSeperator((const char*)input1, &bufSize1);
  ASSERT_STREQ("123456 12345", eraseRet1);

  const char* input2 = "\"123456\\ \n 12345\"";
  uint64 bufSize2 = strlen(input1);
  const char* eraseRet2 = LexUtil::eraseLineSeperator((const char*)input2, &bufSize2);
  ASSERT_STREQ("\"123456 12345\"", eraseRet2);
}
<|endoftext|>


<commit_before>// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "bloaty.h"

#include "absl/strings/substitute.h"

ABSL_ATTRIBUTE_NORETURN
static void Throw(const char *str, int line) {
  throw bloaty::Error(str, __FILE__, line);
}

#define THROW(msg) Throw(msg, __LINE__)
#define THROWF(...) Throw(absl::Substitute(__VA_ARGS__).c_str(), __LINE__)
#define WARN(x) fprintf(stderr, "bloaty: %s\n", x);

using absl::string_view;

namespace bloaty {
namespace wasm {

template <class T>
T ReadMemcpy(string_view* data) {
  T ret;
  if (data->size() < sizeof(T)) {
    THROW("premature EOF reading fixed-length wasm data");
  }
  memcpy(&ret, data->data(), sizeof(T));
  data->remove_prefix(sizeof(T));
  return ret;
}

uint64_t ReadLEB128Internal(bool is_signed, size_t size, string_view* data) {
  uint64_t ret = 0;
  int shift = 0;
  int maxshift = 70;
  const char* ptr = data->data();
  const char* limit = ptr + data->size();

  while (ptr < limit && shift < maxshift) {
    char byte = *(ptr++);
    ret |= static_cast<uint64_t>(byte & 0x7f) << shift;
    shift += 7;
    if ((byte & 0x80) == 0) {
      data->remove_prefix(ptr - data->data());
      if (is_signed && shift < size && (byte & 0x40)) {
        ret |= -(1ULL << shift);
      }
      return ret;
    }
  }

  THROW("corrupt wasm data, unterminated LEB128");
}

bool ReadVarUInt1(string_view* data) {
  return static_cast<bool>(ReadLEB128Internal(false, 1, data));
}

uint8_t ReadVarUInt7(string_view* data) {
  return static_cast<char>(ReadLEB128Internal(false, 7, data));
}

uint32_t ReadVarUInt32(string_view* data) {
  return static_cast<uint32_t>(ReadLEB128Internal(false, 32, data));
}

int8_t ReadVarint7(string_view* data) {
  return static_cast<int8_t>(ReadLEB128Internal(true, 7, data));
}

string_view ReadPiece(size_t bytes, string_view* data) {
  if(data->size() < bytes) {
    THROW("premature EOF reading variable-length DWARF data");
  }
  string_view ret = data->substr(0, bytes);
  data->remove_prefix(bytes);
  return ret;
}

bool ReadMagic(string_view* data) {
  const uint32_t wasm_magic = 0x6d736100;
  uint32_t magic = ReadMemcpy<uint32_t>(data);

  if (magic != wasm_magic) {
    return false;
  }

  // TODO(haberman): do we need to fail if this is >1?
  uint32_t version = ReadMemcpy<uint32_t>(data);
  (void)version;

  return true;
}

class Section {
 public:
  uint32_t id;
  std::string name;
  string_view data;
  string_view contents;

  static Section Read(string_view* data_param) {
    Section ret;
    string_view data = *data_param;
    string_view section_data = data;

    ret.id = ReadVarUInt7(&data);
    uint32_t size = ReadVarUInt32(&data);
    string_view next_section = data.substr(size);
    data = data.substr(0, size);
    size_t header_size = data.data() - section_data.data();
    ret.data = section_data.substr(0, size + header_size);

    if (ret.id == 0) {
      uint32_t name_len = ReadVarUInt32(&data);
      ret.name = std::string(ReadPiece(name_len, &data));
    } else if (ret.id <= 11) {
      ret.name = names[ret.id];
    } else {
      THROWF("Unknown section id: $0", ret.id);
    }

    ret.contents = data;
    *data_param = next_section;
    return ret;
  }

  enum Name {
    kType      = 1,
    kImport    = 2,
    kFunction  = 3,
    kTable     = 4,
    kMemory    = 5,
    kGlobal    = 6,
    kExport    = 7,
    kStart     = 8,
    kElement   = 9,
    kCode      = 10,
    kData      = 11,
  };

  static const char* names[];
};

const char* Section::names[] = {
  "<none>",    // 0
  "Type",      // 1
  "Import",    // 2
  "Function",  // 3
  "Table",     // 4
  "Memory",    // 5
  "Global",    // 6
  "Export",    // 7
  "Start",     // 8
  "Element",   // 9
  "Code",      // 10
  "Data",      // 11
};

struct ExternalKind {
  enum Kind {
    kFunction = 0,
    kTable = 1,
    kMemory = 2,
    kGlobal = 3,
  };
};

template <class Func>
void ForEachSection(string_view file, Func&& section_func) {
  string_view data = file;
  ReadMagic(&data);

  while (!data.empty()) {
    Section section = Section::Read(&data);
    section_func(section);
  }
}

void ParseSections(RangeSink* sink) {
  ForEachSection(sink->input_file().data(), [sink](const Section& section) {
    sink->AddFileRange("wasm_sections", section.name, section.data);
  });
}

typedef std::unordered_map<int, std::string> FuncNames;

void ReadFunctionNames(const Section& section, FuncNames* names,
                       RangeSink* sink) {
  enum class NameType {
    kModule = 0,
    kFunction = 1,
    kLocal = 2,
  };

  string_view data = section.contents;

  while (!data.empty()) {
    char type = ReadVarUInt7(&data);
    uint32_t size = ReadVarUInt32(&data);
    string_view section = data.substr(0, size);
    data = data.substr(size);

    if (static_cast<NameType>(type) == NameType::kFunction) {
      uint32_t count = ReadVarUInt32(&section);
      for (uint32_t i = 0; i < count; i++) {
        string_view entry = section;
        uint32_t index = ReadVarUInt32(&section);
        uint32_t name_len = ReadVarUInt32(&section);
        string_view name = ReadPiece(name_len, &section);
        entry = entry.substr(0, name.data() - entry.data() + name.size());
        sink->AddFileRange("wasm_funcname", name, entry);
        (*names)[index] = std::string(name);
      }
    }
  }
}

int ReadValueType(string_view* data) {
  return ReadVarint7(data);
}

int ReadElemType(string_view* data) {
  return ReadVarint7(data);
}

void ReadResizableLimits(string_view* data) {
  auto flags = ReadVarUInt1(data);
  ReadVarUInt32(data);
  if (flags) {
    ReadVarUInt32(data);
  }
}

void ReadGlobalType(string_view* data) {
  ReadValueType(data);
  ReadVarUInt1(data);
}

void ReadTableType(string_view* data) {
  ReadElemType(data);
  ReadResizableLimits(data);
}

void ReadMemoryType(string_view* data) {
  ReadResizableLimits(data);
}

uint32_t GetNumFunctionImports(const Section& section) {
  assert(section.id == Section::kImport);
  string_view data = section.contents;

  uint32_t count = ReadVarUInt32(&data);
  uint32_t func_count = 0;

  for (uint32_t i = 0; i < count; i++) {
    uint32_t module_len = ReadVarUInt32(&data);
    ReadPiece(module_len, &data);
    uint32_t field_len = ReadVarUInt32(&data);
    ReadPiece(field_len, &data);
    auto kind = ReadMemcpy<uint8_t>(&data);

    switch (kind) {
      case ExternalKind::kFunction:
        func_count++;
        ReadVarUInt32(&data);
        break;
      case ExternalKind::kTable:
        ReadTableType(&data);
        break;
      case ExternalKind::kMemory:
        ReadMemoryType(&data);
        break;
      case ExternalKind::kGlobal:
        ReadGlobalType(&data);
        break;
      default:
        THROWF("Unrecognized import kind: $0", kind);
    }
  }

  return func_count;
}

void ReadCodeSection(const Section& section, const FuncNames& names,
                     uint32_t num_imports, RangeSink* sink) {
  string_view data = section.contents;

  uint32_t count = ReadVarUInt32(&data);

  for (uint32_t i = 0; i < count; i++) {
    string_view func = data;
    uint32_t size = ReadVarUInt32(&data);
    uint32_t total_size = size + (data.data() - func.data());

    func = func.substr(0, total_size);
    data = data.substr(size);

    auto iter = names.find(num_imports + i);

    if (iter == names.end()) {
      std::string name = "func[" + std::to_string(i) + "]";
      sink->AddFileRange("wasm_function", name, func);
    } else {
      sink->AddFileRange("wasm_function", iter->second, func);
    }
  }
}

void ParseSymbols(RangeSink* sink) {
  // First pass: read the custom naming section to get function names.
  std::unordered_map<int, std::string> func_names;
  uint32_t num_imports = 0;

  ForEachSection(sink->input_file().data(),
                 [&func_names, sink](const Section& section) {
                   if (section.name == "name") {
                     ReadFunctionNames(section, &func_names, sink);
                   }
                 });

  // Second pass: read the function/code sections.
  ForEachSection(sink->input_file().data(),
                 [&func_names, &num_imports, sink](const Section& section) {
                   if (section.id == Section::kImport) {
                     num_imports = GetNumFunctionImports(section);
                   } else if (section.id == Section::kCode) {
                     ReadCodeSection(section, func_names, num_imports, sink);
                   }
                 });
}

void AddWebAssemblyFallback(RangeSink* sink) {
  ForEachSection(sink->input_file().data(), [sink](const Section& section) {
    std::string name2 =
        std::string("[section ") + std::string(section.name) + std::string("]");
    sink->AddFileRange("wasm_overhead", name2, section.data);
  });
  sink->AddFileRange("wasm_overhead", "[WASM Header]",
                     sink->input_file().data().substr(0, 8));
}

class WebAssemblyObjectFile : public ObjectFile {
 public:
  WebAssemblyObjectFile(std::unique_ptr<InputFile> file_data)
      : ObjectFile(std::move(file_data)) {}

  std::string GetBuildId() const override {
    // TODO(haberman): does WebAssembly support this?
    return std::string();
  }

  void ProcessFile(const std::vector<RangeSink*>& sinks) const override {
    for (auto sink : sinks) {
      switch (sink->data_source()) {
        case DataSource::kSegments:
        case DataSource::kSections:
          ParseSections(sink);
          break;
        case DataSource::kSymbols:
        case DataSource::kRawSymbols:
        case DataSource::kShortSymbols:
        case DataSource::kFullSymbols:
          ParseSymbols(sink);
          break;
        case DataSource::kArchiveMembers:
        case DataSource::kCompileUnits:
        case DataSource::kInlines:
        default:
          THROW("WebAssembly doesn't support this data source");
      }
      AddWebAssemblyFallback(sink);
    }
  }

  bool GetDisassemblyInfo(absl::string_view /*symbol*/,
                          DataSource /*symbol_source*/,
                          DisassemblyInfo* /*info*/) const override {
    WARN("WebAssembly files do not support disassembly yet");
    return false;
  }
};

}  // namespace wasm

std::unique_ptr<ObjectFile> TryOpenWebAssemblyFile(
    std::unique_ptr<InputFile>& file) {
  string_view data = file->data();
  if (wasm::ReadMagic(&data)) {
    return std::unique_ptr<ObjectFile>(
        new wasm::WebAssemblyObjectFile(std::move(file)));
  }

  return nullptr;
}

}  // namespace bloaty
<commit_msg>Add WASM Demangle<commit_after>// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "bloaty.h"

#include "absl/strings/substitute.h"

ABSL_ATTRIBUTE_NORETURN
static void Throw(const char *str, int line) {
  throw bloaty::Error(str, __FILE__, line);
}

#define THROW(msg) Throw(msg, __LINE__)
#define THROWF(...) Throw(absl::Substitute(__VA_ARGS__).c_str(), __LINE__)
#define WARN(x) fprintf(stderr, "bloaty: %s\n", x);

using absl::string_view;

namespace bloaty {
namespace wasm {

template <class T>
T ReadMemcpy(string_view* data) {
  T ret;
  if (data->size() < sizeof(T)) {
    THROW("premature EOF reading fixed-length wasm data");
  }
  memcpy(&ret, data->data(), sizeof(T));
  data->remove_prefix(sizeof(T));
  return ret;
}

uint64_t ReadLEB128Internal(bool is_signed, size_t size, string_view* data) {
  uint64_t ret = 0;
  int shift = 0;
  int maxshift = 70;
  const char* ptr = data->data();
  const char* limit = ptr + data->size();

  while (ptr < limit && shift < maxshift) {
    char byte = *(ptr++);
    ret |= static_cast<uint64_t>(byte & 0x7f) << shift;
    shift += 7;
    if ((byte & 0x80) == 0) {
      data->remove_prefix(ptr - data->data());
      if (is_signed && shift < size && (byte & 0x40)) {
        ret |= -(1ULL << shift);
      }
      return ret;
    }
  }

  THROW("corrupt wasm data, unterminated LEB128");
}

bool ReadVarUInt1(string_view* data) {
  return static_cast<bool>(ReadLEB128Internal(false, 1, data));
}

uint8_t ReadVarUInt7(string_view* data) {
  return static_cast<char>(ReadLEB128Internal(false, 7, data));
}

uint32_t ReadVarUInt32(string_view* data) {
  return static_cast<uint32_t>(ReadLEB128Internal(false, 32, data));
}

int8_t ReadVarint7(string_view* data) {
  return static_cast<int8_t>(ReadLEB128Internal(true, 7, data));
}

string_view ReadPiece(size_t bytes, string_view* data) {
  if(data->size() < bytes) {
    THROW("premature EOF reading variable-length DWARF data");
  }
  string_view ret = data->substr(0, bytes);
  data->remove_prefix(bytes);
  return ret;
}

bool ReadMagic(string_view* data) {
  const uint32_t wasm_magic = 0x6d736100;
  uint32_t magic = ReadMemcpy<uint32_t>(data);

  if (magic != wasm_magic) {
    return false;
  }

  // TODO(haberman): do we need to fail if this is >1?
  uint32_t version = ReadMemcpy<uint32_t>(data);
  (void)version;

  return true;
}

class Section {
 public:
  uint32_t id;
  std::string name;
  string_view data;
  string_view contents;

  static Section Read(string_view* data_param) {
    Section ret;
    string_view data = *data_param;
    string_view section_data = data;

    ret.id = ReadVarUInt7(&data);
    uint32_t size = ReadVarUInt32(&data);
    string_view next_section = data.substr(size);
    data = data.substr(0, size);
    size_t header_size = data.data() - section_data.data();
    ret.data = section_data.substr(0, size + header_size);

    if (ret.id == 0) {
      uint32_t name_len = ReadVarUInt32(&data);
      ret.name = std::string(ReadPiece(name_len, &data));
    } else if (ret.id <= 11) {
      ret.name = names[ret.id];
    } else {
      THROWF("Unknown section id: $0", ret.id);
    }

    ret.contents = data;
    *data_param = next_section;
    return ret;
  }

  enum Name {
    kType      = 1,
    kImport    = 2,
    kFunction  = 3,
    kTable     = 4,
    kMemory    = 5,
    kGlobal    = 6,
    kExport    = 7,
    kStart     = 8,
    kElement   = 9,
    kCode      = 10,
    kData      = 11,
  };

  static const char* names[];
};

const char* Section::names[] = {
  "<none>",    // 0
  "Type",      // 1
  "Import",    // 2
  "Function",  // 3
  "Table",     // 4
  "Memory",    // 5
  "Global",    // 6
  "Export",    // 7
  "Start",     // 8
  "Element",   // 9
  "Code",      // 10
  "Data",      // 11
};

struct ExternalKind {
  enum Kind {
    kFunction = 0,
    kTable = 1,
    kMemory = 2,
    kGlobal = 3,
  };
};

template <class Func>
void ForEachSection(string_view file, Func&& section_func) {
  string_view data = file;
  ReadMagic(&data);

  while (!data.empty()) {
    Section section = Section::Read(&data);
    section_func(section);
  }
}

void ParseSections(RangeSink* sink) {
  ForEachSection(sink->input_file().data(), [sink](const Section& section) {
    sink->AddFileRange("wasm_sections", section.name, section.data);
  });
}

typedef std::unordered_map<int, std::string> FuncNames;

void ReadFunctionNames(const Section& section, FuncNames* names,
                       RangeSink* sink) {
  enum class NameType {
    kModule = 0,
    kFunction = 1,
    kLocal = 2,
  };

  string_view data = section.contents;

  while (!data.empty()) {
    char type = ReadVarUInt7(&data);
    uint32_t size = ReadVarUInt32(&data);
    string_view section = data.substr(0, size);
    data = data.substr(size);

    if (static_cast<NameType>(type) == NameType::kFunction) {
      uint32_t count = ReadVarUInt32(&section);
      for (uint32_t i = 0; i < count; i++) {
        string_view entry = section;
        uint32_t index = ReadVarUInt32(&section);
        uint32_t name_len = ReadVarUInt32(&section);
        string_view name = ReadPiece(name_len, &section);
        entry = entry.substr(0, name.data() - entry.data() + name.size());
        sink->AddFileRange("wasm_funcname", name, entry);
        (*names)[index] = std::string(name);
      }
    }
  }
}

int ReadValueType(string_view* data) {
  return ReadVarint7(data);
}

int ReadElemType(string_view* data) {
  return ReadVarint7(data);
}

void ReadResizableLimits(string_view* data) {
  auto flags = ReadVarUInt1(data);
  ReadVarUInt32(data);
  if (flags) {
    ReadVarUInt32(data);
  }
}

void ReadGlobalType(string_view* data) {
  ReadValueType(data);
  ReadVarUInt1(data);
}

void ReadTableType(string_view* data) {
  ReadElemType(data);
  ReadResizableLimits(data);
}

void ReadMemoryType(string_view* data) {
  ReadResizableLimits(data);
}

uint32_t GetNumFunctionImports(const Section& section) {
  assert(section.id == Section::kImport);
  string_view data = section.contents;

  uint32_t count = ReadVarUInt32(&data);
  uint32_t func_count = 0;

  for (uint32_t i = 0; i < count; i++) {
    uint32_t module_len = ReadVarUInt32(&data);
    ReadPiece(module_len, &data);
    uint32_t field_len = ReadVarUInt32(&data);
    ReadPiece(field_len, &data);
    auto kind = ReadMemcpy<uint8_t>(&data);

    switch (kind) {
      case ExternalKind::kFunction:
        func_count++;
        ReadVarUInt32(&data);
        break;
      case ExternalKind::kTable:
        ReadTableType(&data);
        break;
      case ExternalKind::kMemory:
        ReadMemoryType(&data);
        break;
      case ExternalKind::kGlobal:
        ReadGlobalType(&data);
        break;
      default:
        THROWF("Unrecognized import kind: $0", kind);
    }
  }

  return func_count;
}

void ReadCodeSection(const Section& section, const FuncNames& names,
                     uint32_t num_imports, RangeSink* sink) {
  string_view data = section.contents;

  uint32_t count = ReadVarUInt32(&data);

  for (uint32_t i = 0; i < count; i++) {
    string_view func = data;
    uint32_t size = ReadVarUInt32(&data);
    uint32_t total_size = size + (data.data() - func.data());

    func = func.substr(0, total_size);
    data = data.substr(size);

    auto iter = names.find(num_imports + i);

    if (iter == names.end()) {
      std::string name = "func[" + std::to_string(i) + "]";
      sink->AddFileRange("wasm_function", name, func);
    } else {
      sink->AddFileRange("wasm_function", ItaniumDemangle(iter->second, sink->data_source()), func);
    }
  }
}

void ParseSymbols(RangeSink* sink) {
  // First pass: read the custom naming section to get function names.
  std::unordered_map<int, std::string> func_names;
  uint32_t num_imports = 0;

  ForEachSection(sink->input_file().data(),
                 [&func_names, sink](const Section& section) {
                   if (section.name == "name") {
                     ReadFunctionNames(section, &func_names, sink);
                   }
                 });

  // Second pass: read the function/code sections.
  ForEachSection(sink->input_file().data(),
                 [&func_names, &num_imports, sink](const Section& section) {
                   if (section.id == Section::kImport) {
                     num_imports = GetNumFunctionImports(section);
                   } else if (section.id == Section::kCode) {
                     ReadCodeSection(section, func_names, num_imports, sink);
                   }
                 });
}

void AddWebAssemblyFallback(RangeSink* sink) {
  ForEachSection(sink->input_file().data(), [sink](const Section& section) {
    std::string name2 =
        std::string("[section ") + std::string(section.name) + std::string("]");
    sink->AddFileRange("wasm_overhead", name2, section.data);
  });
  sink->AddFileRange("wasm_overhead", "[WASM Header]",
                     sink->input_file().data().substr(0, 8));
}

class WebAssemblyObjectFile : public ObjectFile {
 public:
  WebAssemblyObjectFile(std::unique_ptr<InputFile> file_data)
      : ObjectFile(std::move(file_data)) {}

  std::string GetBuildId() const override {
    // TODO(haberman): does WebAssembly support this?
    return std::string();
  }

  void ProcessFile(const std::vector<RangeSink*>& sinks) const override {
    for (auto sink : sinks) {
      switch (sink->data_source()) {
        case DataSource::kSegments:
        case DataSource::kSections:
          ParseSections(sink);
          break;
        case DataSource::kSymbols:
        case DataSource::kRawSymbols:
        case DataSource::kShortSymbols:
        case DataSource::kFullSymbols:
          ParseSymbols(sink);
          break;
        case DataSource::kArchiveMembers:
        case DataSource::kCompileUnits:
        case DataSource::kInlines:
        default:
          THROW("WebAssembly doesn't support this data source");
      }
      AddWebAssemblyFallback(sink);
    }
  }

  bool GetDisassemblyInfo(absl::string_view /*symbol*/,
                          DataSource /*symbol_source*/,
                          DisassemblyInfo* /*info*/) const override {
    WARN("WebAssembly files do not support disassembly yet");
    return false;
  }
};

}  // namespace wasm

std::unique_ptr<ObjectFile> TryOpenWebAssemblyFile(
    std::unique_ptr<InputFile>& file) {
  string_view data = file->data();
  if (wasm::ReadMagic(&data)) {
    return std::unique_ptr<ObjectFile>(
        new wasm::WebAssemblyObjectFile(std::move(file)));
  }

  return nullptr;
}

}  // namespace bloaty
<|endoftext|>