<commit_before>/*

Copyright (c) 2006, Arvid Norberg & Daniel Wallin
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include "libtorrent/time.hpp" // for total_seconds

#include <libtorrent/kademlia/traversal_algorithm.hpp>
#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/kademlia/rpc_manager.hpp>
#include <libtorrent/kademlia/node.hpp>
#include <libtorrent/session_status.hpp>
#include "libtorrent/broadcast_socket.hpp" // for cidr_distance

#include <boost/bind.hpp>

namespace libtorrent { namespace dht
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DEFINE_LOG(traversal)
#endif

observer_ptr traversal_algorithm::new_observer(void* ptr
	, udp::endpoint const& ep, node_id const& id)
{
	observer_ptr o(new (ptr) null_observer(boost::intrusive_ptr<traversal_algorithm>(this), ep, id));
#ifdef TORRENT_DEBUG
	o->m_in_constructor = false;
#endif
	return o;
}

traversal_algorithm::traversal_algorithm(
	node_impl& node
	, node_id target)
	: m_ref_count(0)
	, m_node(node)
	, m_target(target)
	, m_invoke_count(0)
	, m_branch_factor(3)
	, m_responses(0)
	, m_timeouts(0)
	, m_num_target_nodes(m_node.m_table.bucket_size() * 2)
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	TORRENT_LOG(traversal) << " [" << this << "] new traversal process. Target: " << target;
#endif
}

bool compare_ip_cidr(observer_ptr const& lhs, observer_ptr const& rhs)
{
	TORRENT_ASSERT(lhs->target_addr().is_v4() == rhs->target_addr().is_v4());
	// the number of bits in the IPs that may match. If
	// more bits that this matches, something suspicious is
	// going on and we shouldn't add the second one to our
	// routing table
	int cutoff = rhs->target_addr().is_v4() ? 4 : 64;
	int dist = cidr_distance(lhs->target_addr(), rhs->target_addr());
	return dist <= cutoff;
}

void traversal_algorithm::add_entry(node_id const& id, udp::endpoint addr, unsigned char flags)
{
	TORRENT_ASSERT(m_node.m_rpc.allocation_size() >= sizeof(find_data_observer));
	void* ptr = m_node.m_rpc.allocate_observer();
	if (ptr == 0)
	{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << "[" << this << ":" << name()
			<< "] failed to allocate memory for observer. aborting!";
#endif
		done();
		return;
	}
	observer_ptr o = new_observer(ptr, addr, id);
	if (id.is_all_zeros())
	{
		o->set_id(generate_id());
		o->flags |= observer::flag_no_id;
	}

	o->flags |= flags;

	std::vector<observer_ptr>::iterator i = std::lower_bound(
		m_results.begin()
		, m_results.end()
		, o
		, boost::bind(
			compare_ref
			, boost::bind(&observer::id, _1)
			, boost::bind(&observer::id, _2)
			, m_target
		)
	);

	if (i == m_results.end() || (*i)->id() != id)
	{
		if (m_node.settings().restrict_search_ips)
		{
			// don't allow multiple entries from IPs very close to each other
			std::vector<observer_ptr>::iterator j = std::find_if(
				m_results.begin(), m_results.end(), boost::bind(&compare_ip_cidr, _1, o));

			if (j != m_results.end())
			{
				// we already have a node in this search with an IP very
				// close to this one. We know that it's not the same, because
				// it claims a different node-ID. Ignore this to avoid attacks
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(traversal) << "ignoring DHT search entry: " << o->id()
				<< " " << o->target_addr()
				<< " existing node: "
				<< (*j)->id() << " " << (*j)->target_addr();
#endif
				return;
			}
		}
		TORRENT_ASSERT(std::find_if(m_results.begin(), m_results.end()
			, boost::bind(&observer::id, _1) == id) == m_results.end());
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << "[" << this << ":" << name()
			<< "] adding result: " << id << " " << addr;
#endif
		i = m_results.insert(i, o);
	}

	if (m_results.size() > 100) m_results.resize(100);
}

void traversal_algorithm::start()
{
	// in case the routing table is empty, use the
	// router nodes in the table
	if (m_results.empty()) add_router_entries();
	init();
	add_requests();
}

void* traversal_algorithm::allocate_observer()
{
	return m_node.m_rpc.allocate_observer();
}

void traversal_algorithm::free_observer(void* ptr)
{
	m_node.m_rpc.free_observer(ptr);
}

void traversal_algorithm::traverse(node_id const& id, udp::endpoint addr)
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	if (id.is_all_zeros())
		TORRENT_LOG(traversal) << time_now_string() << "[" << this << ":" << name()
			<< "] WARNING: node returned a list which included a node with id 0";
#endif
	add_entry(id, addr, 0);
}

void traversal_algorithm::finished(observer_ptr o)
{
#ifdef TORRENT_DEBUG
	std::vector<observer_ptr>::iterator i = std::find(
		m_results.begin(), m_results.end(), o);

	TORRENT_ASSERT(i != m_results.end() || m_results.size() == 100);
#endif

	// if this flag is set, it means we increased the
	// branch factor for it, and we should restore it
	if (o->flags & observer::flag_short_timeout)
		--m_branch_factor;

	TORRENT_ASSERT(o->flags & observer::flag_queried);
	o->flags |= observer::flag_alive;

	++m_responses;
	--m_invoke_count;
	TORRENT_ASSERT(m_invoke_count >= 0);
	add_requests();
	if (m_invoke_count == 0) done();
}

// prevent request means that the total number of requests has
// overflown. This query failed because it was the oldest one.
// So, if this is true, don't make another request
void traversal_algorithm::failed(observer_ptr o, int flags)
{
	TORRENT_ASSERT(m_invoke_count >= 0);

	if (m_results.empty()) return;

	TORRENT_ASSERT(o->flags & observer::flag_queried);
	if (flags & short_timeout)
	{
		// short timeout means that it has been more than
		// two seconds since we sent the request, and that
		// we'll most likely not get a response. But, in case
		// we do get a late response, keep the handler
		// around for some more, but open up the slot
		// by increasing the branch factor
		if ((o->flags & observer::flag_short_timeout) == 0)
			++m_branch_factor;
		o->flags |= observer::flag_short_timeout;
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << " [" << this << ":" << name()
			<< "] first chance timeout: "
			<< o->id() << " " << o->target_ep()
			<< " branch-factor: " << m_branch_factor
			<< " invoke-count: " << m_invoke_count;
#endif
	}
	else
	{
		o->flags |= observer::flag_failed;
		// if this flag is set, it means we increased the
		// branch factor for it, and we should restore it
		if (o->flags & observer::flag_short_timeout)
			--m_branch_factor;

#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << " [" << this << ":" << name()
			<< "] failed: " << o->id() << " " << o->target_ep()
			<< " branch-factor: " << m_branch_factor
			<< " invoke-count: " << m_invoke_count;
#endif
		// don't tell the routing table about
		// node ids that we just generated ourself
		if ((o->flags & observer::flag_no_id) == 0)
			m_node.m_table.node_failed(o->id(), o->target_ep());
		++m_timeouts;
		--m_invoke_count;
		TORRENT_ASSERT(m_invoke_count >= 0);
	}

	if (flags & prevent_request)
	{
		--m_branch_factor;
		if (m_branch_factor <= 0) m_branch_factor = 1;
	}
	add_requests();
	if (m_invoke_count == 0) done();
}

void traversal_algorithm::done()
{
	// delete all our references to the observer objects so
	// they will in turn release the traversal algorithm
	m_results.clear();
}

namespace
{
	bool bitwise_nand(unsigned char lhs, unsigned char rhs)
	{
		return (lhs & rhs) == 0;
	}
}

void traversal_algorithm::add_requests()
{
	int results_target = m_num_target_nodes;

	// Find the first node that hasn't already been queried.
	for (std::vector<observer_ptr>::iterator i = m_results.begin()
		, end(m_results.end()); i != end
		&& results_target > 0 && m_invoke_count < m_branch_factor; ++i)
	{
		if ((*i)->flags & observer::flag_alive) --results_target;
		if ((*i)->flags & observer::flag_queried) continue;

#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << " [" << this << ":" << name() << "]"
			<< " nodes-left: " << (m_results.end() - i)
			<< " invoke-count: " << m_invoke_count
			<< " branch-factor: " << m_branch_factor;
#endif

		if (invoke(*i))
		{
			TORRENT_ASSERT(m_invoke_count >= 0);
			++m_invoke_count;
			(*i)->flags |= observer::flag_queried;
		}
	}
}

void traversal_algorithm::add_router_entries()
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	TORRENT_LOG(traversal) << " using router nodes to initiate traversal algorithm. "
		<< std::distance(m_node.m_table.router_begin(), m_node.m_table.router_end()) << " routers";
#endif
	for (routing_table::router_iterator i = m_node.m_table.router_begin()
		, end(m_node.m_table.router_end()); i != end; ++i)
	{
		add_entry(node_id(0), *i, observer::flag_initial);
	}
}

void traversal_algorithm::init()
{
	// update the last activity of this bucket
	m_node.m_table.touch_bucket(m_target);
	m_branch_factor = m_node.branch_factor();
	m_node.add_traversal_algorithm(this);
}

traversal_algorithm::~traversal_algorithm()
{
	m_node.remove_traversal_algorithm(this);
}

void traversal_algorithm::status(dht_lookup& l)
{
	l.timeouts = m_timeouts;
	l.responses = m_responses;
	l.outstanding_requests = m_invoke_count;
	l.branch_factor = m_branch_factor;
	l.type = name();
	l.nodes_left = 0;
	l.first_timeout = 0;

	int last_sent = INT_MAX;
	ptime now = time_now();
	for (std::vector<observer_ptr>::iterator i = m_results.begin()
		, end(m_results.end()); i != end; ++i)
	{
		observer& o = **i;
		if (o.flags & observer::flag_queried)
		{
			last_sent = (std::min)(last_sent, total_seconds(now - o.sent()));
			if (o.has_short_timeout()) ++l.first_timeout;
			continue;
		}
		++l.nodes_left;
	}
	l.last_sent = last_sent;
}

} } // namespace libtorrent::dht

<commit_msg>fix DHT cidr check<commit_after>/*

Copyright (c) 2006, Arvid Norberg & Daniel Wallin
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include "libtorrent/time.hpp" // for total_seconds

#include <libtorrent/kademlia/traversal_algorithm.hpp>
#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/kademlia/rpc_manager.hpp>
#include <libtorrent/kademlia/node.hpp>
#include <libtorrent/session_status.hpp>
#include "libtorrent/broadcast_socket.hpp" // for cidr_distance

#include <boost/bind.hpp>

namespace libtorrent { namespace dht
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DEFINE_LOG(traversal)
#endif

observer_ptr traversal_algorithm::new_observer(void* ptr
	, udp::endpoint const& ep, node_id const& id)
{
	observer_ptr o(new (ptr) null_observer(boost::intrusive_ptr<traversal_algorithm>(this), ep, id));
#ifdef TORRENT_DEBUG
	o->m_in_constructor = false;
#endif
	return o;
}

traversal_algorithm::traversal_algorithm(
	node_impl& node
	, node_id target)
	: m_ref_count(0)
	, m_node(node)
	, m_target(target)
	, m_invoke_count(0)
	, m_branch_factor(3)
	, m_responses(0)
	, m_timeouts(0)
	, m_num_target_nodes(m_node.m_table.bucket_size() * 2)
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	TORRENT_LOG(traversal) << " [" << this << "] new traversal process. Target: " << target;
#endif
}

// returns true of lhs and rhs are too close to each other to appear
// in the same DHT search under different node IDs
bool compare_ip_cidr(observer_ptr const& lhs, observer_ptr const& rhs)
{
	if (lhs->target_addr().is_v4() != rhs->target_addr().is_v4())
		return false;
	// the number of bits in the IPs that may match. If
	// more bits that this matches, something suspicious is
	// going on and we shouldn't add the second one to our
	// routing table
	int cutoff = rhs->target_addr().is_v4() ? 4 : 64;
	int dist = cidr_distance(lhs->target_addr(), rhs->target_addr());
	return dist <= cutoff;
}

void traversal_algorithm::add_entry(node_id const& id, udp::endpoint addr, unsigned char flags)
{
	TORRENT_ASSERT(m_node.m_rpc.allocation_size() >= sizeof(find_data_observer));
	void* ptr = m_node.m_rpc.allocate_observer();
	if (ptr == 0)
	{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << "[" << this << ":" << name()
			<< "] failed to allocate memory for observer. aborting!";
#endif
		done();
		return;
	}
	observer_ptr o = new_observer(ptr, addr, id);
	if (id.is_all_zeros())
	{
		o->set_id(generate_id());
		o->flags |= observer::flag_no_id;
	}

	o->flags |= flags;

	std::vector<observer_ptr>::iterator i = std::lower_bound(
		m_results.begin()
		, m_results.end()
		, o
		, boost::bind(
			compare_ref
			, boost::bind(&observer::id, _1)
			, boost::bind(&observer::id, _2)
			, m_target
		)
	);

	if (i == m_results.end() || (*i)->id() != id)
	{
		if (m_node.settings().restrict_search_ips)
		{
			// don't allow multiple entries from IPs very close to each other
			std::vector<observer_ptr>::iterator j = std::find_if(
				m_results.begin(), m_results.end(), boost::bind(&compare_ip_cidr, _1, o));

			if (j != m_results.end())
			{
				// we already have a node in this search with an IP very
				// close to this one. We know that it's not the same, because
				// it claims a different node-ID. Ignore this to avoid attacks
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(traversal) << "ignoring DHT search entry: " << o->id()
				<< " " << o->target_addr()
				<< " existing node: "
				<< (*j)->id() << " " << (*j)->target_addr();
#endif
				return;
			}
		}
		TORRENT_ASSERT(std::find_if(m_results.begin(), m_results.end()
			, boost::bind(&observer::id, _1) == id) == m_results.end());
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << "[" << this << ":" << name()
			<< "] adding result: " << id << " " << addr;
#endif
		i = m_results.insert(i, o);
	}

	if (m_results.size() > 100) m_results.resize(100);
}

void traversal_algorithm::start()
{
	// in case the routing table is empty, use the
	// router nodes in the table
	if (m_results.empty()) add_router_entries();
	init();
	add_requests();
}

void* traversal_algorithm::allocate_observer()
{
	return m_node.m_rpc.allocate_observer();
}

void traversal_algorithm::free_observer(void* ptr)
{
	m_node.m_rpc.free_observer(ptr);
}

void traversal_algorithm::traverse(node_id const& id, udp::endpoint addr)
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	if (id.is_all_zeros())
		TORRENT_LOG(traversal) << time_now_string() << "[" << this << ":" << name()
			<< "] WARNING: node returned a list which included a node with id 0";
#endif
	add_entry(id, addr, 0);
}

void traversal_algorithm::finished(observer_ptr o)
{
#ifdef TORRENT_DEBUG
	std::vector<observer_ptr>::iterator i = std::find(
		m_results.begin(), m_results.end(), o);

	TORRENT_ASSERT(i != m_results.end() || m_results.size() == 100);
#endif

	// if this flag is set, it means we increased the
	// branch factor for it, and we should restore it
	if (o->flags & observer::flag_short_timeout)
		--m_branch_factor;

	TORRENT_ASSERT(o->flags & observer::flag_queried);
	o->flags |= observer::flag_alive;

	++m_responses;
	--m_invoke_count;
	TORRENT_ASSERT(m_invoke_count >= 0);
	add_requests();
	if (m_invoke_count == 0) done();
}

// prevent request means that the total number of requests has
// overflown. This query failed because it was the oldest one.
// So, if this is true, don't make another request
void traversal_algorithm::failed(observer_ptr o, int flags)
{
	TORRENT_ASSERT(m_invoke_count >= 0);

	if (m_results.empty()) return;

	TORRENT_ASSERT(o->flags & observer::flag_queried);
	if (flags & short_timeout)
	{
		// short timeout means that it has been more than
		// two seconds since we sent the request, and that
		// we'll most likely not get a response. But, in case
		// we do get a late response, keep the handler
		// around for some more, but open up the slot
		// by increasing the branch factor
		if ((o->flags & observer::flag_short_timeout) == 0)
			++m_branch_factor;
		o->flags |= observer::flag_short_timeout;
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << " [" << this << ":" << name()
			<< "] first chance timeout: "
			<< o->id() << " " << o->target_ep()
			<< " branch-factor: " << m_branch_factor
			<< " invoke-count: " << m_invoke_count;
#endif
	}
	else
	{
		o->flags |= observer::flag_failed;
		// if this flag is set, it means we increased the
		// branch factor for it, and we should restore it
		if (o->flags & observer::flag_short_timeout)
			--m_branch_factor;

#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << " [" << this << ":" << name()
			<< "] failed: " << o->id() << " " << o->target_ep()
			<< " branch-factor: " << m_branch_factor
			<< " invoke-count: " << m_invoke_count;
#endif
		// don't tell the routing table about
		// node ids that we just generated ourself
		if ((o->flags & observer::flag_no_id) == 0)
			m_node.m_table.node_failed(o->id(), o->target_ep());
		++m_timeouts;
		--m_invoke_count;
		TORRENT_ASSERT(m_invoke_count >= 0);
	}

	if (flags & prevent_request)
	{
		--m_branch_factor;
		if (m_branch_factor <= 0) m_branch_factor = 1;
	}
	add_requests();
	if (m_invoke_count == 0) done();
}

void traversal_algorithm::done()
{
	// delete all our references to the observer objects so
	// they will in turn release the traversal algorithm
	m_results.clear();
}

namespace
{
	bool bitwise_nand(unsigned char lhs, unsigned char rhs)
	{
		return (lhs & rhs) == 0;
	}
}

void traversal_algorithm::add_requests()
{
	int results_target = m_num_target_nodes;

	// Find the first node that hasn't already been queried.
	for (std::vector<observer_ptr>::iterator i = m_results.begin()
		, end(m_results.end()); i != end
		&& results_target > 0 && m_invoke_count < m_branch_factor; ++i)
	{
		if ((*i)->flags & observer::flag_alive) --results_target;
		if ((*i)->flags & observer::flag_queried) continue;

#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << " [" << this << ":" << name() << "]"
			<< " nodes-left: " << (m_results.end() - i)
			<< " invoke-count: " << m_invoke_count
			<< " branch-factor: " << m_branch_factor;
#endif

		if (invoke(*i))
		{
			TORRENT_ASSERT(m_invoke_count >= 0);
			++m_invoke_count;
			(*i)->flags |= observer::flag_queried;
		}
	}
}

void traversal_algorithm::add_router_entries()
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	TORRENT_LOG(traversal) << " using router nodes to initiate traversal algorithm. "
		<< std::distance(m_node.m_table.router_begin(), m_node.m_table.router_end()) << " routers";
#endif
	for (routing_table::router_iterator i = m_node.m_table.router_begin()
		, end(m_node.m_table.router_end()); i != end; ++i)
	{
		add_entry(node_id(0), *i, observer::flag_initial);
	}
}

void traversal_algorithm::init()
{
	// update the last activity of this bucket
	m_node.m_table.touch_bucket(m_target);
	m_branch_factor = m_node.branch_factor();
	m_node.add_traversal_algorithm(this);
}

traversal_algorithm::~traversal_algorithm()
{
	m_node.remove_traversal_algorithm(this);
}

void traversal_algorithm::status(dht_lookup& l)
{
	l.timeouts = m_timeouts;
	l.responses = m_responses;
	l.outstanding_requests = m_invoke_count;
	l.branch_factor = m_branch_factor;
	l.type = name();
	l.nodes_left = 0;
	l.first_timeout = 0;

	int last_sent = INT_MAX;
	ptime now = time_now();
	for (std::vector<observer_ptr>::iterator i = m_results.begin()
		, end(m_results.end()); i != end; ++i)
	{
		observer& o = **i;
		if (o.flags & observer::flag_queried)
		{
			last_sent = (std::min)(last_sent, total_seconds(now - o.sent()));
			if (o.has_short_timeout()) ++l.first_timeout;
			continue;
		}
		++l.nodes_left;
	}
	l.last_sent = last_sent;
}

} } // namespace libtorrent::dht

<|endoftext|>


<commit_before>#include "visualizationWindow.h"
#include "utils.h"
#include <iostream>
#include <gdkmm/general.h>
using namespace kokrotviz;

VisualizationWindow::VisualizationWindow(Gtk::Window* Window, Glib::RefPtr<Gtk::Builder> Builder, LayerManager *LayerMan) :
    mWidget(this), mLayers(LayerMan), mPositionX(0), mPositionY(0), mZoom(1.0), mDragging(false),
    mDragStartX(0), mDragStartY(0), mDragStartPositionX(0), mDragStartPositionY(0.0)
{
    mCanvasContainer = Utils::tryFindWidget<Gtk::Box>("visReferencePoint", Builder);

    mZoomScale = Utils::tryFindWidget<Gtk::Scale>("zoomControl", Builder);
    mZoomScale->signal_value_changed().connect(sigc::mem_fun(*this, &VisualizationWindow::onZoomChanged));

    mCanvasContainer->pack_start(mWidget);

    mWidget.signal_button_press_event().connect(sigc::mem_fun(*this, &VisualizationWindow::onMouseDown));
    mWidget.signal_button_release_event().connect(sigc::mem_fun(*this, &VisualizationWindow::onMouseUp));
    mWidget.signal_motion_notify_event().connect(sigc::mem_fun(*this, &VisualizationWindow::onMouseMove));

    mWidget.add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK);
    mWidget.show();
}

void VisualizationWindow::notifyLayersChange()
{
    mPixbufCache.clear();
    mPositionX = mPositionY = 0;
    mZoom = 1.0;
    mZoomScale->set_value(100.0);
}

void VisualizationWindow::drawElement(const Cairo::RefPtr<Cairo::Context>& cr, const LayerElement& el)
{
    LayerElementType typ = el.Type;
    if (typ == LET_Bitmap) {
        std::cout<<"bekdropz not ded"<<std::endl;
        Glib::RefPtr<Gdk::Pixbuf> pixbuf;
        auto it = mPixbufCache.find(el.Data.B.GUID);

        if (it != mPixbufCache.end()) {
            pixbuf = it->second;
        } else {
            pixbuf = Gdk::Pixbuf::create_from_data((guint8*)el.Data.B.Data,
                Gdk::COLORSPACE_RGB, false, 8, el.Data.B.Width, el.Data.B.Height, 3 * el.Data.B.Width);
            mPixbufCache[el.Data.B.GUID] = pixbuf;
        }

        Gdk::Cairo::set_source_pixbuf(cr, pixbuf);
        Cairo::RefPtr<Cairo::SurfacePattern>::cast_dynamic<Cairo::Pattern>(cr->get_source())->set_filter(Cairo::FILTER_NEAREST);
        cr->rectangle(0, 0, el.Data.B.Width, el.Data.B.Height);
        cr->fill();
    } else if (typ == LET_Polygon) {
        std::cout<<"poligons not dead"<<std::endl;
        cr->move_to(el.Data.Poly.Data[0].X, el.Data.Poly.Data[0].Y);

        for (int i = 0; i < el.Data.Poly.Size; ++i) {
            int j = (i + 1) % el.Data.Poly.Size;
            cr->line_to(el.Data.Poly.Data[j].X, el.Data.Poly.Data[j].Y);
        }
        cr->stroke();
    } else if (typ == LET_Point) {
        cr->move_to(el.Data.P.X, el.Data.P.Y);
        cr->line_to(el.Data.P.X, el.Data.P.Y);
        cr->stroke();
    } else if (typ == LET_Line) {
        cr->move_to(el.Data.L.A.X, el.Data.L.A.Y);
        cr->line_to(el.Data.L.B.X, el.Data.L.B.Y);
        cr->stroke();
    }

}

void VisualizationWindow::onZoomChanged()
{
    mZoom = mZoomScale->get_value() / 100.0;
    mWidget.queue_draw();
}

void VisualizationWindow::drawLayer(const Cairo::RefPtr<Cairo::Context>& cr, const Layer& l)
{
    const std::vector<LayerElement>& elems = l.getElements();
    for (auto& elem : elems) {
        Color c = l.getColor();
        cr->set_source_rgba(c.R / 255.0, c.G / 255.0, c.B / 255.0, l.getOpacity() / 255.0);
        /* cr->set_source_rgba(1, 0, 0, 1); //l.getOpacity() / 255.0); */
        cr->set_line_cap(Cairo::LINE_CAP_ROUND);
        cr->set_line_width(l.getLineWidth() / mZoom);

        drawElement(cr, elem);
    }
}

bool VisualizationWindow::onDraw(const Cairo::RefPtr<Cairo::Context>& cr)
{
    std::pair<dimension, dimension> dims = mLayers->getCanvasDimensions();
    Gtk::Allocation alloc = mWidget.get_allocation();
    const int ww = alloc.get_width(), wh = alloc.get_height();

    cr->set_identity_matrix();
    cr->translate(mPositionX - mZoom * dims.first / 2 + ww / 2, mPositionY - mZoom * dims.second / 2 + wh / 2);
    cr->scale(mZoom, mZoom);

    mLayers->visitLayers(Delegate<void(kok_debug_class, Layer&)>::fromCallable(
            [this, cr] (kok_debug_class, Layer& layer) {
                if (layer.getVisible()) {
                    std::lock_guard<std::recursive_mutex> ll(layer.Mutex);
                    drawLayer(cr, layer);
                }
            }));
}

void VisualizationWindow::redraw()
{
    mWidget.queue_draw();
}

bool VisualizationWindow::onMouseMove(GdkEventMotion* evt)
{
    if (mDragging) {
        double dx = - mDragStartX + evt->x, dy = - mDragStartY + evt->y;
        mPositionX = mDragStartPositionX + dx;
        mPositionY = mDragStartPositionY + dy;

        mWidget.queue_draw();
    }
}

bool VisualizationWindow::onMouseDown(GdkEventButton* evt)
{
    if (evt->type == GDK_BUTTON_PRESS && evt->button == 1) {
        mDragging = true;
        mDragStartX = evt->x;
        mDragStartY = evt->y;
        mDragStartPositionX = mPositionX;
        mDragStartPositionY = mPositionY;
    }
}

bool VisualizationWindow::onMouseUp(GdkEventButton* evt)
{
    if (evt->type == GDK_BUTTON_RELEASE && evt->button == 1) {
        mDragging = false;
    }
}

<commit_msg>Remove annoying stdout debug output from kokrotviz<commit_after>#include "visualizationWindow.h"
#include "utils.h"
#include <iostream>
#include <gdkmm/general.h>
using namespace kokrotviz;

VisualizationWindow::VisualizationWindow(Gtk::Window* Window, Glib::RefPtr<Gtk::Builder> Builder, LayerManager *LayerMan) :
    mWidget(this), mLayers(LayerMan), mPositionX(0), mPositionY(0), mZoom(1.0), mDragging(false),
    mDragStartX(0), mDragStartY(0), mDragStartPositionX(0), mDragStartPositionY(0.0)
{
    mCanvasContainer = Utils::tryFindWidget<Gtk::Box>("visReferencePoint", Builder);

    mZoomScale = Utils::tryFindWidget<Gtk::Scale>("zoomControl", Builder);
    mZoomScale->signal_value_changed().connect(sigc::mem_fun(*this, &VisualizationWindow::onZoomChanged));

    mCanvasContainer->pack_start(mWidget);

    mWidget.signal_button_press_event().connect(sigc::mem_fun(*this, &VisualizationWindow::onMouseDown));
    mWidget.signal_button_release_event().connect(sigc::mem_fun(*this, &VisualizationWindow::onMouseUp));
    mWidget.signal_motion_notify_event().connect(sigc::mem_fun(*this, &VisualizationWindow::onMouseMove));

    mWidget.add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK);
    mWidget.show();
}

void VisualizationWindow::notifyLayersChange()
{
    mPixbufCache.clear();
    mPositionX = mPositionY = 0;
    mZoom = 1.0;
    mZoomScale->set_value(100.0);
}

void VisualizationWindow::drawElement(const Cairo::RefPtr<Cairo::Context>& cr, const LayerElement& el)
{
    LayerElementType typ = el.Type;
    if (typ == LET_Bitmap) {
        Glib::RefPtr<Gdk::Pixbuf> pixbuf;
        auto it = mPixbufCache.find(el.Data.B.GUID);

        if (it != mPixbufCache.end()) {
            pixbuf = it->second;
        } else {
            pixbuf = Gdk::Pixbuf::create_from_data((guint8*)el.Data.B.Data,
                Gdk::COLORSPACE_RGB, false, 8, el.Data.B.Width, el.Data.B.Height, 3 * el.Data.B.Width);
            mPixbufCache[el.Data.B.GUID] = pixbuf;
        }

        Gdk::Cairo::set_source_pixbuf(cr, pixbuf);
        Cairo::RefPtr<Cairo::SurfacePattern>::cast_dynamic<Cairo::Pattern>(cr->get_source())->set_filter(Cairo::FILTER_NEAREST);
        cr->rectangle(0, 0, el.Data.B.Width, el.Data.B.Height);
        cr->fill();
    } else if (typ == LET_Polygon) {
        cr->move_to(el.Data.Poly.Data[0].X, el.Data.Poly.Data[0].Y);

        for (int i = 0; i < el.Data.Poly.Size; ++i) {
            int j = (i + 1) % el.Data.Poly.Size;
            cr->line_to(el.Data.Poly.Data[j].X, el.Data.Poly.Data[j].Y);
        }
        cr->stroke();
    } else if (typ == LET_Point) {
        cr->move_to(el.Data.P.X, el.Data.P.Y);
        cr->line_to(el.Data.P.X, el.Data.P.Y);
        cr->stroke();
    } else if (typ == LET_Line) {
        cr->move_to(el.Data.L.A.X, el.Data.L.A.Y);
        cr->line_to(el.Data.L.B.X, el.Data.L.B.Y);
        cr->stroke();
    }

}

void VisualizationWindow::onZoomChanged()
{
    mZoom = mZoomScale->get_value() / 100.0;
    mWidget.queue_draw();
}

void VisualizationWindow::drawLayer(const Cairo::RefPtr<Cairo::Context>& cr, const Layer& l)
{
    const std::vector<LayerElement>& elems = l.getElements();
    for (auto& elem : elems) {
        Color c = l.getColor();
        cr->set_source_rgba(c.R / 255.0, c.G / 255.0, c.B / 255.0, l.getOpacity() / 255.0);
        /* cr->set_source_rgba(1, 0, 0, 1); //l.getOpacity() / 255.0); */
        cr->set_line_cap(Cairo::LINE_CAP_ROUND);
        cr->set_line_width(l.getLineWidth() / mZoom);

        drawElement(cr, elem);
    }
}

bool VisualizationWindow::onDraw(const Cairo::RefPtr<Cairo::Context>& cr)
{
    std::pair<dimension, dimension> dims = mLayers->getCanvasDimensions();
    Gtk::Allocation alloc = mWidget.get_allocation();
    const int ww = alloc.get_width(), wh = alloc.get_height();

    cr->set_identity_matrix();
    cr->translate(mPositionX - mZoom * dims.first / 2 + ww / 2, mPositionY - mZoom * dims.second / 2 + wh / 2);
    cr->scale(mZoom, mZoom);

    mLayers->visitLayers(Delegate<void(kok_debug_class, Layer&)>::fromCallable(
            [this, cr] (kok_debug_class, Layer& layer) {
                if (layer.getVisible()) {
                    std::lock_guard<std::recursive_mutex> ll(layer.Mutex);
                    drawLayer(cr, layer);
                }
            }));
}

void VisualizationWindow::redraw()
{
    mWidget.queue_draw();
}

bool VisualizationWindow::onMouseMove(GdkEventMotion* evt)
{
    if (mDragging) {
        double dx = - mDragStartX + evt->x, dy = - mDragStartY + evt->y;
        mPositionX = mDragStartPositionX + dx;
        mPositionY = mDragStartPositionY + dy;

        mWidget.queue_draw();
    }
}

bool VisualizationWindow::onMouseDown(GdkEventButton* evt)
{
    if (evt->type == GDK_BUTTON_PRESS && evt->button == 1) {
        mDragging = true;
        mDragStartX = evt->x;
        mDragStartY = evt->y;
        mDragStartPositionX = mPositionX;
        mDragStartPositionY = mPositionY;
    }
}

bool VisualizationWindow::onMouseUp(GdkEventButton* evt)
{
    if (evt->type == GDK_BUTTON_RELEASE && evt->button == 1) {
        mDragging = false;
    }
}

<|endoftext|>


<commit_before>/*
 * ModSecurity, http://www.modsecurity.org/
 * Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
 *
 * 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
 *
 * If any of the files related to licensing are missing or if you have any
 * other questions related to licensing please contact Trustwave Holdings, Inc.
 * directly using the email address security@modsecurity.org.
 *
 */

#include "src/macro_expansion.h"
#include "modsecurity/transaction.h"

namespace modsecurity {

MacroExpansion::MacroExpansion() { }

std::string MacroExpansion::expandKeepOriginal(const std::string& input,
    Transaction *transaction) {
    std::string a = MacroExpansion::expand(input, transaction);

    if (a != input) {
        return "\"" + a + "\" (Was: " + input + ")";
    }

    return input;
}

std::string MacroExpansion::expand(const std::string& input,
    Transaction *transaction) {
    std::string res;
    size_t pos = input.find("%{");

    if (pos != std::string::npos) {
        res = input;
    } else {
        return input;
    }

    while (pos != std::string::npos) {
        size_t start = pos;
        size_t end = res.find("}");
        if (end == std::string::npos) {
            return res;
        }
        std::string variable(res, start + 2, end - (start + 2));
        std::string *variableValue;
        size_t collection = variable.find(".");
        if (collection == std::string::npos) {
            variableValue = transaction->m_collections.resolveFirst(variable);
        } else {
            std::string col = std::string(variable, 0, collection);
            std::string var = std::string(variable, collection + 1,
                variable.length() - (collection + 1));
            variableValue = transaction->m_collections.resolveFirst(col, var);
        }

        if (res[end - start + 2] == '%') {
            res.erase(start, end - start + 1);
        } else {
            res.erase(start, end - start + 2);
        }
        if (variableValue != NULL) {
            res.insert(start, *variableValue);
        }

        pos = res.find("%{");
    }

    return res;
}

}  // namespace modsecurity
<commit_msg>Fix macro expansion: no more % abandoned by the end of variable<commit_after>/*
 * ModSecurity, http://www.modsecurity.org/
 * Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
 *
 * 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
 *
 * If any of the files related to licensing are missing or if you have any
 * other questions related to licensing please contact Trustwave Holdings, Inc.
 * directly using the email address security@modsecurity.org.
 *
 */

#include "src/macro_expansion.h"
#include "modsecurity/transaction.h"

namespace modsecurity {

MacroExpansion::MacroExpansion() { }

std::string MacroExpansion::expandKeepOriginal(const std::string& input,
    Transaction *transaction) {
    std::string a = MacroExpansion::expand(input, transaction);

    if (a != input) {
        return "\"" + a + "\" (Was: " + input + ")";
    }

    return input;
}

std::string MacroExpansion::expand(const std::string& input,
    Transaction *transaction) {
    std::string res;
    size_t pos = input.find("%{");

    if (pos != std::string::npos) {
        res = input;
    } else {
        return input;
    }

    while (pos != std::string::npos) {
        size_t start = pos;
        size_t end = res.find("}");
        if (end == std::string::npos) {
            return res;
        }
        std::string variable(res, start + 2, end - (start + 2));
        std::string *variableValue;
        size_t collection = variable.find(".");
        if (collection == std::string::npos) {
            variableValue = transaction->m_collections.resolveFirst(variable);
        } else {
            std::string col = std::string(variable, 0, collection);
            std::string var = std::string(variable, collection + 1,
                variable.length() - (collection + 1));
            variableValue = transaction->m_collections.resolveFirst(col, var);
        }

        res.erase(start, end - start + 1);
        if (res[start] == '%') {
            res.erase(start, 1);
        }

        if (variableValue != NULL) {
            res.insert(start, *variableValue);
        }

        pos = res.find("%{");
    }

    return res;
}

}  // namespace modsecurity
<|endoftext|>


<commit_before>#include <utility>
#include <cmath>
#include <limits>

#include "core/Rand.h"

//Default constructor
Rand::Rand()
{
	//Initialize to the default seed
	setSeed(DEFAULT_SEED);
}

//Seed constructor
Rand::Rand(uint32_t seed)
{
	//Initialize to the provided seed
	setSeed(seed);
}

//Copy constructor
Rand::Rand(const Rand& src)
{
	_reg_a = src._reg_a;
	_reg_b = src._reg_b;
	_reg_c = src._reg_c;
}

//Register constructor
Rand::Rand(uint32_t src_reg_a, uint32_t src_reg_b, uint32_t src_reg_c)
{
	if(!setRegisters(src_reg_a, src_reg_b, src_reg_c))
	{
		//If we fail to set the registers, fall back to our default seed
		setSeed(DEFAULT_SEED);
	}
}

//Assignment operator
Rand& Rand::operator=(const Rand& rhs)
{
	Rand tmp(rhs);

	std::swap(_reg_a, tmp._reg_a);
	std::swap(_reg_b, tmp._reg_b);
	std::swap(_reg_c, tmp._reg_c);

	return *this;
}

//(Re)Set the internal state to the specified seed.
void Rand::setSeed(uint32_t seed)
{
	if(0 == seed)
	{
		//Cannot accept 0, fall back to the default
		seed = DEFAULT_SEED;
	}

	//Seed registers with our seed value
	if(!setRegisters(seed, seed, seed))
	{
		//We failed, means at least one register got nothing in the low bits
		if(!setRegisters(seed, seed, seed>>(REG_WIDTH_INT-REG_WIDTH_C)))
		{
			//Failed again, means both lower register got nothing
			//This one won't fail because we already know it's a non-0 seed
			setRegisters(seed, seed>>(REG_WIDTH_INT-REG_WIDTH_B), seed>>(REG_WIDTH_INT-REG_WIDTH_C));
		}
	}

	//Shuffle in some entropy
	//Also ensures the three registers are fully different now
	for(int i = 0; i < 32; i++)
	{
		randBit();
	}
}

//Set the internal register state directly
bool Rand::setRegisters(uint32_t src_reg_a, uint32_t src_reg_b, uint32_t src_reg_c)
{
	//Mask the inputs to fit into our registers
	src_reg_a &= REG_MASK_A;
	src_reg_b &= REG_MASK_B;
	src_reg_c &= REG_MASK_C;

	if(0 == src_reg_a || 0 == src_reg_b || 0 == src_reg_c)
	{
		return false; //We cannot set registers to 0
	}

	_reg_a = src_reg_a;
	_reg_b = src_reg_b;
	_reg_c = src_reg_c;

	return true;
}

//Retrieve the internal register state
void Rand::getRegisters(uint32_t& dst_reg_a, uint32_t& dst_reg_b, uint32_t& dst_reg_c)
{
	dst_reg_a = _reg_a;
	dst_reg_b = _reg_b;
	dst_reg_c = _reg_c;
}

//Get a single random bit
uint8_t Rand::randBit()
{
	return updateRegister(_reg_a, Rand::LFRS_MASK_A)
		 ^ updateRegister(_reg_b, Rand::LFRS_MASK_B)
		 ^ updateRegister(_reg_c, Rand::LFRS_MASK_C);
}

//Return n random bits as uint32_t
uint32_t Rand::randN(uint32_t n)
{
	uint32_t bits = 0;

	if(32 < n)
	{
		//We will only return 32 bits max, period
		n = 32;
	}

	for(uint32_t i = 0; i < n; i++)
	{
		bits <<= 1;
		bits |= randBit();
	}

	return bits;
}

//Return a random integer between min and max (inclusive)
uint32_t Rand::randInt(uint32_t min, uint32_t max)
{
	uint32_t diff = max - min;

	//How many bits in diff?
	uint32_t bits = 1;
	uint32_t mask = 1;
	while(mask < diff)
	{
		mask <<= 1;
		mask |= 1;
		++bits;
	}

	//Now we'll get a random number of the appropriate bit size
	uint32_t number;
	while(diff < (number = randN(bits))) { };

	return min + number;
}

//Generate a random floating-point value
double Rand::randFloat()
{
	//Get a 32-bit uint, then divide it by the maximum possible 32-bit uint;
	//this gives us a floating-point value between 0.0 and 1.0.
	return (double)rand32() / (double)Rand::RAND_MAX_INT;
}

double Rand::randGauss(double mu, double sigma)
{
	//atan(1)*4 is apparently pi, so multiplying by 8 instead gets us 2pi
	static const double two_pi = 8.0 * std::atan(1.0);

	//Store our generated pair so we only have to generate one every other call
	static double z0, z1;
	//And keep track of whether or not we've got one to return already
	static bool generate = false; //We're going to reverse it...

	generate = !generate; //...right here!

	if(false == generate)
	{
		//Return the second of our previously-generated pair, after transforming
		//to fit the requested mu and sigma.
		return z1 * sigma + mu;
	}

	//Generate a new pair
	double u1, u2;
	do {
		u1 = randFloat();
		u2 = randFloat();
	} while( u1 <= std::numeric_limits<double>::min() );

	//This is the magic of the Box-Muller transform
	z0 = sqrt(-2.0 * log(u1)) * cos(two_pi * u2);
	z1 = sqrt(-2.0 * log(u1)) * sin(two_pi * u2);

	//Transform our random normal value to match our requested mu and sigma
	return z0 * sigma + mu;
}

//Update the supplied register, and return the next bit in the sequence
uint8_t Rand::updateRegister(uint32_t& reg, uint32_t mask)
{
	uint8_t lsb = reg & 1;
	reg >>= 1;

	if(1 == lsb)
	{
		reg ^= mask;
	}

	return lsb;
}

<commit_msg>More documentation for randGauss; now uses epsilon method.<commit_after>#include <utility>
#include <cmath>
#include <limits>

#include "core/Rand.h"

//Default constructor
Rand::Rand()
{
	//Initialize to the default seed
	setSeed(DEFAULT_SEED);
}

//Seed constructor
Rand::Rand(uint32_t seed)
{
	//Initialize to the provided seed
	setSeed(seed);
}

//Copy constructor
Rand::Rand(const Rand& src)
{
	_reg_a = src._reg_a;
	_reg_b = src._reg_b;
	_reg_c = src._reg_c;
}

//Register constructor
Rand::Rand(uint32_t src_reg_a, uint32_t src_reg_b, uint32_t src_reg_c)
{
	if(!setRegisters(src_reg_a, src_reg_b, src_reg_c))
	{
		//If we fail to set the registers, fall back to our default seed
		setSeed(DEFAULT_SEED);
	}
}

//Assignment operator
Rand& Rand::operator=(const Rand& rhs)
{
	Rand tmp(rhs);

	std::swap(_reg_a, tmp._reg_a);
	std::swap(_reg_b, tmp._reg_b);
	std::swap(_reg_c, tmp._reg_c);

	return *this;
}

//(Re)Set the internal state to the specified seed.
void Rand::setSeed(uint32_t seed)
{
	if(0 == seed)
	{
		//Cannot accept 0, fall back to the default
		seed = DEFAULT_SEED;
	}

	//Seed registers with our seed value
	if(!setRegisters(seed, seed, seed))
	{
		//We failed, means at least one register got nothing in the low bits
		if(!setRegisters(seed, seed, seed>>(REG_WIDTH_INT-REG_WIDTH_C)))
		{
			//Failed again, means both lower register got nothing
			//This one won't fail because we already know it's a non-0 seed
			setRegisters(seed, seed>>(REG_WIDTH_INT-REG_WIDTH_B), seed>>(REG_WIDTH_INT-REG_WIDTH_C));
		}
	}

	//Shuffle in some entropy
	//Also ensures the three registers are fully different now
	for(int i = 0; i < 32; i++)
	{
		randBit();
	}
}

//Set the internal register state directly
bool Rand::setRegisters(uint32_t src_reg_a, uint32_t src_reg_b, uint32_t src_reg_c)
{
	//Mask the inputs to fit into our registers
	src_reg_a &= REG_MASK_A;
	src_reg_b &= REG_MASK_B;
	src_reg_c &= REG_MASK_C;

	if(0 == src_reg_a || 0 == src_reg_b || 0 == src_reg_c)
	{
		return false; //We cannot set registers to 0
	}

	_reg_a = src_reg_a;
	_reg_b = src_reg_b;
	_reg_c = src_reg_c;

	return true;
}

//Retrieve the internal register state
void Rand::getRegisters(uint32_t& dst_reg_a, uint32_t& dst_reg_b, uint32_t& dst_reg_c)
{
	dst_reg_a = _reg_a;
	dst_reg_b = _reg_b;
	dst_reg_c = _reg_c;
}

//Get a single random bit
uint8_t Rand::randBit()
{
	return updateRegister(_reg_a, Rand::LFRS_MASK_A)
		 ^ updateRegister(_reg_b, Rand::LFRS_MASK_B)
		 ^ updateRegister(_reg_c, Rand::LFRS_MASK_C);
}

//Return n random bits as uint32_t
uint32_t Rand::randN(uint32_t n)
{
	uint32_t bits = 0;

	if(32 < n)
	{
		//We will only return 32 bits max, period
		n = 32;
	}

	for(uint32_t i = 0; i < n; i++)
	{
		bits <<= 1;
		bits |= randBit();
	}

	return bits;
}

//Return a random integer between min and max (inclusive)
uint32_t Rand::randInt(uint32_t min, uint32_t max)
{
	uint32_t diff = max - min;

	//How many bits in diff?
	uint32_t bits = 1;
	uint32_t mask = 1;
	while(mask < diff)
	{
		mask <<= 1;
		mask |= 1;
		++bits;
	}

	//Now we'll get a random number of the appropriate bit size
	uint32_t number;
	while(diff < (number = randN(bits))) { };

	return min + number;
}

//Generate a random floating-point value
double Rand::randFloat()
{
	//Get a 32-bit uint, then divide it by the maximum possible 32-bit uint;
	//this gives us a floating-point value between 0.0 and 1.0.
	return (double)rand32() / (double)Rand::RAND_MAX_INT;
}

/**
 * This implementation is based upon the C implementation found here:
 * http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
 * I took a few liberties with the code to better fit my style and conventions,
 * and to take advantage of the randFloat method available to me, but this
 * code otherwise follows that sample implementation.
 */
double Rand::randGauss(double mu, double sigma)
{
	//atan(1)*4 is apparently pi, so multiplying by 8 instead gets us 2pi
	static const double two_pi = 8.0 * std::atan(1.0);

	//Store our generated pair so we only have to generate one every other call
	static double z0, z1;
	//And keep track of whether or not we've got one to return already
	static bool generate = false; //We're going to reverse it...

	generate = !generate; //...right here!

	if(false == generate)
	{
		//Return the second of our previously-generated pair, after transforming
		//to fit the requested mu and sigma.
		return z1 * sigma + mu;
	}

	//Generate a new pair
	double u1, u2;
	do {
		u1 = randFloat();
		u2 = randFloat();
	} while( u1 <= std::numeric_limits<double>::epsilon() );

	//This is the magic of the Box-Muller transform
	z0 = sqrt(-2.0 * log(u1)) * cos(two_pi * u2);
	z1 = sqrt(-2.0 * log(u1)) * sin(two_pi * u2);

	//Transform our random normal value to match our requested mu and sigma
	return z0 * sigma + mu;
}

//Update the supplied register, and return the next bit in the sequence
uint8_t Rand::updateRegister(uint32_t& reg, uint32_t mask)
{
	uint8_t lsb = reg & 1;
	reg >>= 1;

	if(1 == lsb)
	{
		reg ^= mask;
	}

	return lsb;
}

<|endoftext|>


<commit_before>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

   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 "paddle/framework/backward.h"

#include <list>
#include <memory>

#include "paddle/framework/op_registry.h"
#include "paddle/operators/net_op.h"
#include "paddle/operators/recurrent_op.h"

namespace paddle {
namespace framework {

template <typename Map, typename T>
static void ForEachVarName(const Map& names, T callback) {
  for (auto& name : names) {
    for (auto& n : name.second) {
      if (callback(n)) return;
    }
  }
}

// return whether all the names + suffixes in the set
static bool AllInSet(
    const std::map<std::string, std::vector<std::string>>& names,
    const std::string& suffix, const std::unordered_set<std::string>& set) {
  bool all_in_set = true;
  ForEachVarName(names, [&all_in_set, &set, &suffix](const std::string& n) {
    all_in_set = set.find(n + suffix) != set.end();
    return !all_in_set;
  });
  return all_in_set;
}

static std::unique_ptr<OperatorBase> NOP() {
  auto net_op = new operators::NetOp();
  net_op->SetType("@NOP@");
  net_op->CompleteAddOp();
  return std::unique_ptr<OperatorBase>(net_op);
}

//  Get backward operator from a forward operator, a recursive implementation.
//
//  no_grad_names the gradient variable names without gradient calculating.
//
//  uniq_id is a unique index used inside recursively calling
//  BackwardRecursive. use `uid = uniq_id++;` to get the unique index, and
//  pass `uniq_id` through recursive calling.
//
//  returns The backward operator. In a simple situation, it may be a simple
//  operator, in a complex situation, it maybe a NetOp.
//
//  See Backward.h for details
static std::unique_ptr<OperatorBase> BackwardRecursive(
    const OperatorBase& forwardOp,
    std::unordered_set<std::string>& no_grad_names, size_t& uniq_id) {
  //  If all input gradients of forwarding operator do not need to calculate,
  //  just return an NOP. Not return null ptr because NOP does not take
  //  too much time for calculation, but it is useful for simplifying logic.
  if (AllInSet(forwardOp.Inputs() /*names*/, kGradVarSuffix /*suffix*/,
               no_grad_names /*set*/)) {
    return NOP();
  }

  //  All output gradients of forwarding operator do not need to calculate.
  //  Then all input gradients cannot be computed at all, and we put them into
  //  `no_grad_names` set. Return an NOP.
  if (AllInSet(forwardOp.Outputs() /*names*/, kGradVarSuffix /*suffix*/,
               no_grad_names /*set*/)) {
    ForEachVarName(forwardOp.Inputs(),
                   [&no_grad_names](const std::string& name) -> bool {
                     no_grad_names.insert(GradVarName(name));
                     return false;
                   });
    return NOP();
  }

  // Returned gradient network
  auto net = std::unique_ptr<operators::NetOp>(new operators::NetOp());

  if (forwardOp.IsNetOp()) {
    // Because forwardOp is a net op, it can static_cast.
    auto& forwardNet = static_cast<const operators::NetOp&>(forwardOp);

    // Map from output gradient variable name to operator's indices in
    // backward net's ops_. That operator generates that variable.
    std::unordered_map<std::string, std::vector<size_t>> dup_output_ops;

    size_t local_op_id = 0;
    // reversely travel forwardNet and collect all duplicate outputs.
    for (auto it = forwardNet.ops_.rbegin(); it != forwardNet.ops_.rend();
         ++it, ++local_op_id) {
      auto& fwd = *it;
      auto bwd = BackwardRecursive(*fwd, no_grad_names, uniq_id);
      ForEachVarName(bwd->Outputs(),
                     [&dup_output_ops, local_op_id](const std::string& out) {
                       dup_output_ops[out].emplace_back(local_op_id);
                       return false;
                     });
      net->AppendOp(std::move(bwd));
    }
    // Get unique ID for this method.
    auto uid = uniq_id++;
    // TODO(dzh): more comment
    // multiple operators which have the same output (y for example) may
    // overwrite the same y variable when backward, special operations are token
    // to handle this case. For each duplicate output, rename it to an alias
    // (original name with a offset), append an `add` op for its operator,
    // and finally sum all the alias variable to the final output variable y.
    using Pos = std::pair<size_t, std::unique_ptr<OperatorBase>>;
    std::list<Pos> insert_position;
    for (auto& dup_output_op : dup_output_ops) {
      const std::string& name = dup_output_op.first;
      // duplicate @Empty@ don't need to be added
      if (name == kEmptyVarName) continue;

      auto& dup_op = dup_output_op.second;
      // no duplicate output
      if (dup_op.size() == 1) continue;

      // process the duplicate outputs
      std::vector<std::string> dup_outputs;
      for (size_t i = 0; i < dup_op.size(); ++i) {
        // rename each duplicate output to an alias
        auto op_offset = dup_op[i];
        dup_outputs.push_back(name + "@RENAME@" + std::to_string(uid) + "@" +
                              std::to_string(i));
        net->ops_[op_offset]->Rename(name, dup_outputs.back());
      }
      // collect all the offset to append `add` op for each alias
      //
      // one variable is shared between multiple operators.
      // insert add operator one by one, then add it to output
      if (dup_outputs.size() == 2) {
        insert_position.push_back(
            {dup_op.back(),
             OpRegistry::CreateOp(
                 "add", {{"X", {dup_outputs[0]}}, {"Y", {dup_outputs[1]}}},
                 {{"Out", {name}}}, {})});
      } else {
        for (size_t output_idx = 0; output_idx < dup_outputs.size() - 1;
             ++output_idx) {
          auto insert_add_x = dup_outputs[output_idx];
          auto insert_add_y = dup_outputs[output_idx];
          auto insert_add_out = name + "@SHARED@" + std::to_string(output_idx);
          // first add op inserted
          if (output_idx == dup_outputs.size() - 1) {
            insert_add_out = name;
          }
          if (output_idx != 0) {
            insert_add_y = name + "@SHARED@" + std::to_string(output_idx);
          }
          insert_position.push_back(
              {dup_op.back(),
               OpRegistry::CreateOp(
                   "add", {{"X", {insert_add_x}}, {"Y", {insert_add_y}}},
                   {{"Out", {insert_add_out}}}, {})});
        }
      }
    }

    // make sure the inserted `add` ops follow the BFS order.
    insert_position.sort(
        [](const Pos& l, const Pos& r) { return l.first > r.first; });

    for (auto& pos : insert_position) {
      net->InsertOp(pos.first + 1, std::move(pos.second));
    }
  } else {
    std::unique_ptr<OperatorBase> grad_op(OpRegistry::CreateGradOp(forwardOp));

    ForEachVarName(grad_op->Inputs(), [&no_grad_names, &net, &grad_op](
                                          const std::string& grad_input) {
      if (no_grad_names.count(grad_input)) {
        // +1 for \0
        std::string prefix = grad_input.substr(
            0, grad_input.size() - sizeof(kGradVarSuffix) / sizeof(char) + 1);
        grad_op->Rename(grad_input, prefix + kZeroVarSuffix);

        // If part of input gradient of that operator is not calculated, fill
        // zero variables to that input gradient.
        net->AppendOp(OpRegistry::CreateOp("fill_zeros_like", {{"X", {prefix}}},
                                           {{"Y", {grad_input}}}, {}));
      }
      return false;
    });

    ForEachVarName(grad_op->Outputs(),
                   [&no_grad_names, &grad_op](const std::string& grad_output) {
                     if (no_grad_names.count(grad_output)) {
                       grad_op->Rename(grad_output, kEmptyVarName);
                     }
                     return false;
                   });

    // process recurrent gradient op as a special operator.
    if (forwardOp.Type() == "recurrent") {
      // NOTE clean up cycle call somewhere (RNN's stepnet constains itself), or
      // this will result in infinite loop.
      const auto& rnnop =
          *static_cast<const operators::RecurrentOp*>(&forwardOp);
      auto rnn_grad_op =
          static_cast<operators::RecurrentGradientOp*>(grad_op.get());
      const auto& stepnet_op =
          *static_cast<const OperatorBase*>(&rnnop.stepnet());
      // create stepnet's gradient op
      rnn_grad_op->set_stepnet(
          BackwardRecursive(stepnet_op, no_grad_names, uniq_id));
    }

    if (net->ops_.empty()) {  // Current no aux op is added to network
      return grad_op;
    }
    net->AppendOp(std::move(grad_op));
  }
  net->SetType("@GENERATED_BACKWARD@");
  net->CompleteAddOp();
  return std::unique_ptr<OperatorBase>(
      static_cast<OperatorBase*>(net.release()));
}

// See header for comments
std::unique_ptr<OperatorBase> Backward(
    const OperatorBase& forwardOp,
    const std::unordered_set<std::string>& no_grad_vars) {
  std::unordered_set<std::string> no_grad_names;
  no_grad_names.reserve(no_grad_vars.size() + 1);

  no_grad_names.insert(std::string(kEmptyVarName) + kGradVarSuffix);

  for (auto& name : no_grad_vars) {
    no_grad_names.insert(name + kGradVarSuffix);
  }
  size_t uid = 0;
  return BackwardRecursive(forwardOp, no_grad_names, uid);
}

}  // namespace framework
}  // namespace paddle
<commit_msg>fix typo<commit_after>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

   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 "paddle/framework/backward.h"

#include <list>
#include <memory>

#include "paddle/framework/op_registry.h"
#include "paddle/operators/net_op.h"
#include "paddle/operators/recurrent_op.h"

namespace paddle {
namespace framework {

template <typename Map, typename T>
static void ForEachVarName(const Map& names, T callback) {
  for (auto& name : names) {
    for (auto& n : name.second) {
      if (callback(n)) return;
    }
  }
}

// return whether all the names + suffixes in the set
static bool AllInSet(
    const std::map<std::string, std::vector<std::string>>& names,
    const std::string& suffix, const std::unordered_set<std::string>& set) {
  bool all_in_set = true;
  ForEachVarName(names, [&all_in_set, &set, &suffix](const std::string& n) {
    all_in_set = set.find(n + suffix) != set.end();
    return !all_in_set;
  });
  return all_in_set;
}

static std::unique_ptr<OperatorBase> NOP() {
  auto net_op = new operators::NetOp();
  net_op->SetType("@NOP@");
  net_op->CompleteAddOp();
  return std::unique_ptr<OperatorBase>(net_op);
}

//  Get backward operator from a forward operator, a recursive implementation.
//
//  no_grad_names the gradient variable names without gradient calculating.
//
//  uniq_id is a unique index used inside recursively calling
//  BackwardRecursive. use `uid = uniq_id++;` to get the unique index, and
//  pass `uniq_id` through recursive calling.
//
//  returns The backward operator. In a simple situation, it may be a simple
//  operator, in a complex situation, it maybe a NetOp.
//
//  See Backward.h for details
static std::unique_ptr<OperatorBase> BackwardRecursive(
    const OperatorBase& forwardOp,
    std::unordered_set<std::string>& no_grad_names, size_t& uniq_id) {
  //  If all input gradients of forwarding operator do not need to calculate,
  //  just return an NOP. Not return null ptr because NOP does not take
  //  too much time for calculation, but it is useful for simplifying logic.
  if (AllInSet(forwardOp.Inputs() /*names*/, kGradVarSuffix /*suffix*/,
               no_grad_names /*set*/)) {
    return NOP();
  }

  //  All output gradients of forwarding operator do not need to calculate.
  //  Then all input gradients cannot be computed at all, and we put them into
  //  `no_grad_names` set. Return an NOP.
  if (AllInSet(forwardOp.Outputs() /*names*/, kGradVarSuffix /*suffix*/,
               no_grad_names /*set*/)) {
    ForEachVarName(forwardOp.Inputs(),
                   [&no_grad_names](const std::string& name) -> bool {
                     no_grad_names.insert(GradVarName(name));
                     return false;
                   });
    return NOP();
  }

  // Returned gradient network
  auto net = std::unique_ptr<operators::NetOp>(new operators::NetOp());

  if (forwardOp.IsNetOp()) {
    // Because forwardOp is a net op, it can static_cast.
    auto& forwardNet = static_cast<const operators::NetOp&>(forwardOp);

    // Map from output gradient variable name to operator's indices in
    // backward net's ops_. That operator generates that variable.
    std::unordered_map<std::string, std::vector<size_t>> dup_output_ops;

    size_t local_op_id = 0;
    // reversely travel forwardNet and collect all duplicate outputs.
    for (auto it = forwardNet.ops_.rbegin(); it != forwardNet.ops_.rend();
         ++it, ++local_op_id) {
      auto& fwd = *it;
      auto bwd = BackwardRecursive(*fwd, no_grad_names, uniq_id);
      ForEachVarName(bwd->Outputs(),
                     [&dup_output_ops, local_op_id](const std::string& out) {
                       dup_output_ops[out].emplace_back(local_op_id);
                       return false;
                     });
      net->AppendOp(std::move(bwd));
    }
    // Get unique ID for this method.
    auto uid = uniq_id++;
    // TODO(dzh): more comment
    // multiple operators which have the same output (y for example) may
    // overwrite the same y variable when backward, special operations are token
    // to handle this case. For each duplicate output, rename it to an alias
    // (original name with a offset), append an `add` op for its operator,
    // and finally sum all the alias variable to the final output variable y.
    using Pos = std::pair<size_t, std::unique_ptr<OperatorBase>>;
    std::list<Pos> insert_position;
    for (auto& dup_output_op : dup_output_ops) {
      const std::string& name = dup_output_op.first;
      // duplicate @Empty@ don't need to be added
      if (name == kEmptyVarName) continue;

      auto& dup_op = dup_output_op.second;
      // no duplicate output
      if (dup_op.size() == 1) continue;

      // process the duplicate outputs
      std::vector<std::string> dup_outputs;
      for (size_t i = 0; i < dup_op.size(); ++i) {
        // rename each duplicate output to an alias
        auto op_offset = dup_op[i];
        dup_outputs.push_back(name + "@RENAME@" + std::to_string(uid) + "@" +
                              std::to_string(i));
        net->ops_[op_offset]->Rename(name, dup_outputs.back());
      }
      // collect all the offset to append `add` op for each alias
      //
      // one variable is shared between multiple operators.
      // insert add operator one by one, then add it to output
      if (dup_outputs.size() == 2) {
        insert_position.push_back(
            {dup_op.back(),
             OpRegistry::CreateOp(
                 "add", {{"X", {dup_outputs[0]}}, {"Y", {dup_outputs[1]}}},
                 {{"Out", {name}}}, {})});
      } else {
        for (size_t output_idx = 0; output_idx < dup_outputs.size() - 1;
             ++output_idx) {
          auto insert_add_x = dup_outputs[output_idx];
          auto insert_add_y = dup_outputs[output_idx];
          auto insert_add_out = name + "@SHARED@" + std::to_string(output_idx);
          // first add op inserted
          if (output_idx == dup_outputs.size() - 1) {
            insert_add_out = name;
          }
          if (output_idx != 0) {
            insert_add_y = name + "@SHARED@" + std::to_string(output_idx-1);
          }
          insert_position.push_back(
              {dup_op.back(),
               OpRegistry::CreateOp(
                   "add", {{"X", {insert_add_x}}, {"Y", {insert_add_y}}},
                   {{"Out", {insert_add_out}}}, {})});
        }
      }
    }

    // make sure the inserted `add` ops follow the BFS order.
    insert_position.sort(
        [](const Pos& l, const Pos& r) { return l.first > r.first; });

    for (auto& pos : insert_position) {
      net->InsertOp(pos.first + 1, std::move(pos.second));
    }
  } else {
    std::unique_ptr<OperatorBase> grad_op(OpRegistry::CreateGradOp(forwardOp));

    ForEachVarName(grad_op->Inputs(), [&no_grad_names, &net, &grad_op](
                                          const std::string& grad_input) {
      if (no_grad_names.count(grad_input)) {
        // +1 for \0
        std::string prefix = grad_input.substr(
            0, grad_input.size() - sizeof(kGradVarSuffix) / sizeof(char) + 1);
        grad_op->Rename(grad_input, prefix + kZeroVarSuffix);

        // If part of input gradient of that operator is not calculated, fill
        // zero variables to that input gradient.
        net->AppendOp(OpRegistry::CreateOp("fill_zeros_like", {{"X", {prefix}}},
                                           {{"Y", {grad_input}}}, {}));
      }
      return false;
    });

    ForEachVarName(grad_op->Outputs(),
                   [&no_grad_names, &grad_op](const std::string& grad_output) {
                     if (no_grad_names.count(grad_output)) {
                       grad_op->Rename(grad_output, kEmptyVarName);
                     }
                     return false;
                   });

    // process recurrent gradient op as a special operator.
    if (forwardOp.Type() == "recurrent") {
      // NOTE clean up cycle call somewhere (RNN's stepnet constains itself), or
      // this will result in infinite loop.
      const auto& rnnop =
          *static_cast<const operators::RecurrentOp*>(&forwardOp);
      auto rnn_grad_op =
          static_cast<operators::RecurrentGradientOp*>(grad_op.get());
      const auto& stepnet_op =
          *static_cast<const OperatorBase*>(&rnnop.stepnet());
      // create stepnet's gradient op
      rnn_grad_op->set_stepnet(
          BackwardRecursive(stepnet_op, no_grad_names, uniq_id));
    }

    if (net->ops_.empty()) {  // Current no aux op is added to network
      return grad_op;
    }
    net->AppendOp(std::move(grad_op));
  }
  net->SetType("@GENERATED_BACKWARD@");
  net->CompleteAddOp();
  return std::unique_ptr<OperatorBase>(
      static_cast<OperatorBase*>(net.release()));
}

// See header for comments
std::unique_ptr<OperatorBase> Backward(
    const OperatorBase& forwardOp,
    const std::unordered_set<std::string>& no_grad_vars) {
  std::unordered_set<std::string> no_grad_names;
  no_grad_names.reserve(no_grad_vars.size() + 1);

  no_grad_names.insert(std::string(kEmptyVarName) + kGradVarSuffix);

  for (auto& name : no_grad_vars) {
    no_grad_names.insert(name + kGradVarSuffix);
  }
  size_t uid = 0;
  return BackwardRecursive(forwardOp, no_grad_names, uid);
}

}  // namespace framework
}  // namespace paddle
<|endoftext|>


<commit_before>//===-- RISCVELFObjectWriter.cpp - RISCV ELF Writer -----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "MCTargetDesc/RISCVMCTargetDesc.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCFixup.h"
#include "llvm/Support/ErrorHandling.h"

using namespace llvm;

namespace {
class RISCVELFObjectWriter : public MCELFObjectTargetWriter {
public:
  RISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit);

  ~RISCVELFObjectWriter() override;

protected:
  unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                        const MCFixup &Fixup, bool IsPCRel) const override;
};
}

RISCVELFObjectWriter::RISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit)
    : MCELFObjectTargetWriter(Is64Bit, OSABI, ELF::EM_RISCV,
                              /*HasRelocationAddend*/ false) {}

RISCVELFObjectWriter::~RISCVELFObjectWriter() {}

unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,
                                            const MCValue &Target,
                                            const MCFixup &Fixup,
                                            bool IsPCRel) const {
  llvm_unreachable("invalid fixup kind!");
}

MCObjectWriter *llvm::createRISCVELFObjectWriter(raw_pwrite_stream &OS,
                                                 uint8_t OSABI, bool Is64Bit) {
  MCELFObjectTargetWriter *MOTW = new RISCVELFObjectWriter(OSABI, Is64Bit);
  return createELFObjectWriter(MOTW, OS, /*IsLittleEndian*/ true);
}
<commit_msg>[RISCV] Set HasRelocationAddend for RISCVELFObjectWriter<commit_after>//===-- RISCVELFObjectWriter.cpp - RISCV ELF Writer -----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "MCTargetDesc/RISCVMCTargetDesc.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCFixup.h"
#include "llvm/Support/ErrorHandling.h"

using namespace llvm;

namespace {
class RISCVELFObjectWriter : public MCELFObjectTargetWriter {
public:
  RISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit);

  ~RISCVELFObjectWriter() override;

protected:
  unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                        const MCFixup &Fixup, bool IsPCRel) const override;
};
}

RISCVELFObjectWriter::RISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit)
    : MCELFObjectTargetWriter(Is64Bit, OSABI, ELF::EM_RISCV,
                              /*HasRelocationAddend*/ true) {}

RISCVELFObjectWriter::~RISCVELFObjectWriter() {}

unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,
                                            const MCValue &Target,
                                            const MCFixup &Fixup,
                                            bool IsPCRel) const {
  llvm_unreachable("invalid fixup kind!");
}

MCObjectWriter *llvm::createRISCVELFObjectWriter(raw_pwrite_stream &OS,
                                                 uint8_t OSABI, bool Is64Bit) {
  MCELFObjectTargetWriter *MOTW = new RISCVELFObjectWriter(OSABI, Is64Bit);
  return createELFObjectWriter(MOTW, OS, /*IsLittleEndian*/ true);
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// linux_ptrace_dumper.cc: Implement google_breakpad::LinuxPtraceDumper.
// See linux_ptrace_dumper.h for detals.
// This class was originally splitted from google_breakpad::LinuxDumper.

// This code deals with the mechanics of getting information about a crashed
// process. Since this code may run in a compromised address space, the same
// rules apply as detailed at the top of minidump_writer.h: no libc calls and
// use the alternative allocator.

#include "client/linux/minidump_writer/linux_ptrace_dumper.h"

#include <asm/ptrace.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/uio.h>
#include <sys/wait.h>

#if defined(__i386)
#include <cpuid.h>
#endif

#include "client/linux/minidump_writer/directory_reader.h"
#include "client/linux/minidump_writer/line_reader.h"
#include "common/linux/linux_libc_support.h"
#include "third_party/lss/linux_syscall_support.h"

// Suspends a thread by attaching to it.
static bool SuspendThread(pid_t pid) {
  // This may fail if the thread has just died or debugged.
  errno = 0;
  if (sys_ptrace(PTRACE_ATTACH, pid, NULL, NULL) != 0 &&
      errno != 0) {
    return false;
  }
  while (sys_waitpid(pid, NULL, __WALL) < 0) {
    if (errno != EINTR) {
      sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
      return false;
    }
  }
#if defined(__i386) || defined(__x86_64)
  // On x86, the stack pointer is NULL or -1, when executing trusted code in
  // the seccomp sandbox. Not only does this cause difficulties down the line
  // when trying to dump the thread's stack, it also results in the minidumps
  // containing information about the trusted threads. This information is
  // generally completely meaningless and just pollutes the minidumps.
  // We thus test the stack pointer and exclude any threads that are part of
  // the seccomp sandbox's trusted code.
  user_regs_struct regs;
  if (sys_ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1 ||
#if defined(__i386)
      !regs.esp
#elif defined(__x86_64)
      !regs.rsp
#endif
      ) {
    sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
    return false;
  }
#endif
  return true;
}

// Resumes a thread by detaching from it.
static bool ResumeThread(pid_t pid) {
  return sys_ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0;
}

namespace google_breakpad {

LinuxPtraceDumper::LinuxPtraceDumper(pid_t pid)
    : LinuxDumper(pid),
      threads_suspended_(false) {
}

bool LinuxPtraceDumper::BuildProcPath(char* path, pid_t pid,
                                      const char* node) const {
  if (!path || !node || pid <= 0)
    return false;

  size_t node_len = my_strlen(node);
  if (node_len == 0)
    return false;

  const unsigned pid_len = my_uint_len(pid);
  const size_t total_length = 6 + pid_len + 1 + node_len;
  if (total_length >= NAME_MAX)
    return false;

  my_memcpy(path, "/proc/", 6);
  my_uitos(path + 6, pid, pid_len);
  path[6 + pid_len] = '/';
  my_memcpy(path + 6 + pid_len + 1, node, node_len);
  path[total_length] = '\0';
  return true;
}

void LinuxPtraceDumper::CopyFromProcess(void* dest, pid_t child,
                                        const void* src, size_t length) {
  unsigned long tmp = 55;
  size_t done = 0;
  static const size_t word_size = sizeof(tmp);
  uint8_t* const local = (uint8_t*) dest;
  uint8_t* const remote = (uint8_t*) src;

  while (done < length) {
    const size_t l = (length - done > word_size) ? word_size : (length - done);
    if (sys_ptrace(PTRACE_PEEKDATA, child, remote + done, &tmp) == -1) {
      tmp = 0;
    }
    my_memcpy(local + done, &tmp, l);
    done += l;
  }
}

// Read thread info from /proc/$pid/status.
// Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailable,
// these members are set to -1. Returns true iff all three members are
// available.
bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
  if (index >= threads_.size())
    return false;

  pid_t tid = threads_[index];

  assert(info != NULL);
  char status_path[NAME_MAX];
  if (!BuildProcPath(status_path, tid, "status"))
    return false;

  const int fd = sys_open(status_path, O_RDONLY, 0);
  if (fd < 0)
    return false;

  LineReader* const line_reader = new(allocator_) LineReader(fd);
  const char* line;
  unsigned line_len;

  info->ppid = info->tgid = -1;

  while (line_reader->GetNextLine(&line, &line_len)) {
    if (my_strncmp("Tgid:\t", line, 6) == 0) {
      my_strtoui(&info->tgid, line + 6);
    } else if (my_strncmp("PPid:\t", line, 6) == 0) {
      my_strtoui(&info->ppid, line + 6);
    }

    line_reader->PopLine(line_len);
  }
  sys_close(fd);

  if (info->ppid == -1 || info->tgid == -1)
    return false;

#ifdef PTRACE_GETREGSET
  struct iovec io;
  io.iov_base = &info->regs;
  io.iov_len = sizeof(info->regs);
  if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, (void*)&io) == -1) {
    return false;
  }

  io.iov_base = &info->fpregs;
  io.iov_len = sizeof(info->fpregs);
  if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, (void*)&io) == -1) {
    return false;
  }
#else
  if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1) {
    return false;
  }

  if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) {
    return false;
  }
#endif

#if defined(__i386)
#if !defined(bit_FXSAVE)  // e.g. Clang
#define bit_FXSAVE bit_FXSR
#endif
  // Detect if the CPU supports the FXSAVE/FXRSTOR instructions
  int eax, ebx, ecx, edx;
  __cpuid(1, eax, ebx, ecx, edx);
  if (edx & bit_FXSAVE) {
    if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1) {
      return false;
    }
  } else {
    memset(&info->fpxregs, 0, sizeof(info->fpxregs));
  }
#endif  // defined(__i386)

#if defined(__i386) || defined(__x86_64)
  for (unsigned i = 0; i < ThreadInfo::kNumDebugRegisters; ++i) {
    if (sys_ptrace(
        PTRACE_PEEKUSER, tid,
        reinterpret_cast<void*> (offsetof(struct user,
                                          u_debugreg[0]) + i *
                                 sizeof(debugreg_t)),
        &info->dregs[i]) == -1) {
      return false;
    }
  }
#endif

#if defined(__mips__)
  for (int i = 0; i < 3; ++i) {
    sys_ptrace(PTRACE_PEEKUSER, tid,
               reinterpret_cast<void*>(DSP_BASE + (i * 2)), &info->hi[i]);
    sys_ptrace(PTRACE_PEEKUSER, tid,
               reinterpret_cast<void*>(DSP_BASE + (i * 2) + 1), &info->lo[i]);
  }
  sys_ptrace(PTRACE_PEEKUSER, tid,
             reinterpret_cast<void*>(DSP_CONTROL), &info->dsp_control);
#endif

  const uint8_t* stack_pointer;
#if defined(__i386)
  my_memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp));
#elif defined(__x86_64)
  my_memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp));
#elif defined(__ARM_EABI__)
  my_memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp));
#elif defined(__aarch64__)
  my_memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp));
#elif defined(__mips__)
  stack_pointer =
      reinterpret_cast<uint8_t*>(info->regs.regs[MD_CONTEXT_MIPS_REG_SP]);
#else
#error "This code hasn't been ported to your platform yet."
#endif
  info->stack_pointer = reinterpret_cast<uintptr_t>(stack_pointer);

  return true;
}

bool LinuxPtraceDumper::IsPostMortem() const {
  return false;
}

bool LinuxPtraceDumper::ThreadsSuspend() {
  if (threads_suspended_)
    return true;
  for (size_t i = 0; i < threads_.size(); ++i) {
    if (!SuspendThread(threads_[i])) {
      // If the thread either disappeared before we could attach to it, or if
      // it was part of the seccomp sandbox's trusted code, it is OK to
      // silently drop it from the minidump.
      my_memmove(&threads_[i], &threads_[i+1],
                 (threads_.size() - i - 1) * sizeof(threads_[i]));
      threads_.resize(threads_.size() - 1);
      --i;
    }
  }
  threads_suspended_ = true;
  return threads_.size() > 0;
}

bool LinuxPtraceDumper::ThreadsResume() {
  if (!threads_suspended_)
    return false;
  bool good = true;
  for (size_t i = 0; i < threads_.size(); ++i)
    good &= ResumeThread(threads_[i]);
  threads_suspended_ = false;
  return good;
}

// Parse /proc/$pid/task to list all the threads of the process identified by
// pid.
bool LinuxPtraceDumper::EnumerateThreads() {
  char task_path[NAME_MAX];
  if (!BuildProcPath(task_path, pid_, "task"))
    return false;

  const int fd = sys_open(task_path, O_RDONLY | O_DIRECTORY, 0);
  if (fd < 0)
    return false;
  DirectoryReader* dir_reader = new(allocator_) DirectoryReader(fd);

  // The directory may contain duplicate entries which we filter by assuming
  // that they are consecutive.
  int last_tid = -1;
  const char* dent_name;
  while (dir_reader->GetNextEntry(&dent_name)) {
    if (my_strcmp(dent_name, ".") &&
        my_strcmp(dent_name, "..")) {
      int tid = 0;
      if (my_strtoui(&tid, dent_name) &&
          last_tid != tid) {
        last_tid = tid;
        threads_.push_back(tid);
      }
    }
    dir_reader->PopEntry();
  }

  sys_close(fd);
  return true;
}

}  // namespace google_breakpad
<commit_msg>Stop calling memmove when unnecessary<commit_after>// Copyright (c) 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// linux_ptrace_dumper.cc: Implement google_breakpad::LinuxPtraceDumper.
// See linux_ptrace_dumper.h for detals.
// This class was originally splitted from google_breakpad::LinuxDumper.

// This code deals with the mechanics of getting information about a crashed
// process. Since this code may run in a compromised address space, the same
// rules apply as detailed at the top of minidump_writer.h: no libc calls and
// use the alternative allocator.

#include "client/linux/minidump_writer/linux_ptrace_dumper.h"

#include <asm/ptrace.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/uio.h>
#include <sys/wait.h>

#if defined(__i386)
#include <cpuid.h>
#endif

#include "client/linux/minidump_writer/directory_reader.h"
#include "client/linux/minidump_writer/line_reader.h"
#include "common/linux/linux_libc_support.h"
#include "third_party/lss/linux_syscall_support.h"

// Suspends a thread by attaching to it.
static bool SuspendThread(pid_t pid) {
  // This may fail if the thread has just died or debugged.
  errno = 0;
  if (sys_ptrace(PTRACE_ATTACH, pid, NULL, NULL) != 0 &&
      errno != 0) {
    return false;
  }
  while (sys_waitpid(pid, NULL, __WALL) < 0) {
    if (errno != EINTR) {
      sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
      return false;
    }
  }
#if defined(__i386) || defined(__x86_64)
  // On x86, the stack pointer is NULL or -1, when executing trusted code in
  // the seccomp sandbox. Not only does this cause difficulties down the line
  // when trying to dump the thread's stack, it also results in the minidumps
  // containing information about the trusted threads. This information is
  // generally completely meaningless and just pollutes the minidumps.
  // We thus test the stack pointer and exclude any threads that are part of
  // the seccomp sandbox's trusted code.
  user_regs_struct regs;
  if (sys_ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1 ||
#if defined(__i386)
      !regs.esp
#elif defined(__x86_64)
      !regs.rsp
#endif
      ) {
    sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
    return false;
  }
#endif
  return true;
}

// Resumes a thread by detaching from it.
static bool ResumeThread(pid_t pid) {
  return sys_ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0;
}

namespace google_breakpad {

LinuxPtraceDumper::LinuxPtraceDumper(pid_t pid)
    : LinuxDumper(pid),
      threads_suspended_(false) {
}

bool LinuxPtraceDumper::BuildProcPath(char* path, pid_t pid,
                                      const char* node) const {
  if (!path || !node || pid <= 0)
    return false;

  size_t node_len = my_strlen(node);
  if (node_len == 0)
    return false;

  const unsigned pid_len = my_uint_len(pid);
  const size_t total_length = 6 + pid_len + 1 + node_len;
  if (total_length >= NAME_MAX)
    return false;

  my_memcpy(path, "/proc/", 6);
  my_uitos(path + 6, pid, pid_len);
  path[6 + pid_len] = '/';
  my_memcpy(path + 6 + pid_len + 1, node, node_len);
  path[total_length] = '\0';
  return true;
}

void LinuxPtraceDumper::CopyFromProcess(void* dest, pid_t child,
                                        const void* src, size_t length) {
  unsigned long tmp = 55;
  size_t done = 0;
  static const size_t word_size = sizeof(tmp);
  uint8_t* const local = (uint8_t*) dest;
  uint8_t* const remote = (uint8_t*) src;

  while (done < length) {
    const size_t l = (length - done > word_size) ? word_size : (length - done);
    if (sys_ptrace(PTRACE_PEEKDATA, child, remote + done, &tmp) == -1) {
      tmp = 0;
    }
    my_memcpy(local + done, &tmp, l);
    done += l;
  }
}

// Read thread info from /proc/$pid/status.
// Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailable,
// these members are set to -1. Returns true iff all three members are
// available.
bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
  if (index >= threads_.size())
    return false;

  pid_t tid = threads_[index];

  assert(info != NULL);
  char status_path[NAME_MAX];
  if (!BuildProcPath(status_path, tid, "status"))
    return false;

  const int fd = sys_open(status_path, O_RDONLY, 0);
  if (fd < 0)
    return false;

  LineReader* const line_reader = new(allocator_) LineReader(fd);
  const char* line;
  unsigned line_len;

  info->ppid = info->tgid = -1;

  while (line_reader->GetNextLine(&line, &line_len)) {
    if (my_strncmp("Tgid:\t", line, 6) == 0) {
      my_strtoui(&info->tgid, line + 6);
    } else if (my_strncmp("PPid:\t", line, 6) == 0) {
      my_strtoui(&info->ppid, line + 6);
    }

    line_reader->PopLine(line_len);
  }
  sys_close(fd);

  if (info->ppid == -1 || info->tgid == -1)
    return false;

#ifdef PTRACE_GETREGSET
  struct iovec io;
  io.iov_base = &info->regs;
  io.iov_len = sizeof(info->regs);
  if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, (void*)&io) == -1) {
    return false;
  }

  io.iov_base = &info->fpregs;
  io.iov_len = sizeof(info->fpregs);
  if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, (void*)&io) == -1) {
    return false;
  }
#else
  if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1) {
    return false;
  }

  if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) {
    return false;
  }
#endif

#if defined(__i386)
#if !defined(bit_FXSAVE)  // e.g. Clang
#define bit_FXSAVE bit_FXSR
#endif
  // Detect if the CPU supports the FXSAVE/FXRSTOR instructions
  int eax, ebx, ecx, edx;
  __cpuid(1, eax, ebx, ecx, edx);
  if (edx & bit_FXSAVE) {
    if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1) {
      return false;
    }
  } else {
    memset(&info->fpxregs, 0, sizeof(info->fpxregs));
  }
#endif  // defined(__i386)

#if defined(__i386) || defined(__x86_64)
  for (unsigned i = 0; i < ThreadInfo::kNumDebugRegisters; ++i) {
    if (sys_ptrace(
        PTRACE_PEEKUSER, tid,
        reinterpret_cast<void*> (offsetof(struct user,
                                          u_debugreg[0]) + i *
                                 sizeof(debugreg_t)),
        &info->dregs[i]) == -1) {
      return false;
    }
  }
#endif

#if defined(__mips__)
  for (int i = 0; i < 3; ++i) {
    sys_ptrace(PTRACE_PEEKUSER, tid,
               reinterpret_cast<void*>(DSP_BASE + (i * 2)), &info->hi[i]);
    sys_ptrace(PTRACE_PEEKUSER, tid,
               reinterpret_cast<void*>(DSP_BASE + (i * 2) + 1), &info->lo[i]);
  }
  sys_ptrace(PTRACE_PEEKUSER, tid,
             reinterpret_cast<void*>(DSP_CONTROL), &info->dsp_control);
#endif

  const uint8_t* stack_pointer;
#if defined(__i386)
  my_memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp));
#elif defined(__x86_64)
  my_memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp));
#elif defined(__ARM_EABI__)
  my_memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp));
#elif defined(__aarch64__)
  my_memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp));
#elif defined(__mips__)
  stack_pointer =
      reinterpret_cast<uint8_t*>(info->regs.regs[MD_CONTEXT_MIPS_REG_SP]);
#else
#error "This code hasn't been ported to your platform yet."
#endif
  info->stack_pointer = reinterpret_cast<uintptr_t>(stack_pointer);

  return true;
}

bool LinuxPtraceDumper::IsPostMortem() const {
  return false;
}

bool LinuxPtraceDumper::ThreadsSuspend() {
  if (threads_suspended_)
    return true;
  for (size_t i = 0; i < threads_.size(); ++i) {
    if (!SuspendThread(threads_[i])) {
      // If the thread either disappeared before we could attach to it, or if
      // it was part of the seccomp sandbox's trusted code, it is OK to
      // silently drop it from the minidump.
      if (i < threads_.size() - 1) {
        my_memmove(&threads_[i], &threads_[i + 1],
                   (threads_.size() - i - 1) * sizeof(threads_[i]));
      }
      threads_.resize(threads_.size() - 1);
      --i;
    }
  }
  threads_suspended_ = true;
  return threads_.size() > 0;
}

bool LinuxPtraceDumper::ThreadsResume() {
  if (!threads_suspended_)
    return false;
  bool good = true;
  for (size_t i = 0; i < threads_.size(); ++i)
    good &= ResumeThread(threads_[i]);
  threads_suspended_ = false;
  return good;
}

// Parse /proc/$pid/task to list all the threads of the process identified by
// pid.
bool LinuxPtraceDumper::EnumerateThreads() {
  char task_path[NAME_MAX];
  if (!BuildProcPath(task_path, pid_, "task"))
    return false;

  const int fd = sys_open(task_path, O_RDONLY | O_DIRECTORY, 0);
  if (fd < 0)
    return false;
  DirectoryReader* dir_reader = new(allocator_) DirectoryReader(fd);

  // The directory may contain duplicate entries which we filter by assuming
  // that they are consecutive.
  int last_tid = -1;
  const char* dent_name;
  while (dir_reader->GetNextEntry(&dent_name)) {
    if (my_strcmp(dent_name, ".") &&
        my_strcmp(dent_name, "..")) {
      int tid = 0;
      if (my_strtoui(&tid, dent_name) &&
          last_tid != tid) {
        last_tid = tid;
        threads_.push_back(tid);
      }
    }
    dir_reader->PopEntry();
  }

  sys_close(fd);
  return true;
}

}  // namespace google_breakpad
<|endoftext|>