aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar David Leverton <levertond@googlemail.com> 2007-10-29 00:45:13 +0000
committerAvatar David Leverton <levertond@googlemail.com> 2007-10-29 00:45:13 +0000
commit3c79509ed74583db28b106b772b463f2d5d28dba (patch)
treee3e92a4e1ddc465365b70c561a0ec82352b07345
parent578b688ea64303ad7f75de8bc8d2af29520febd9 (diff)
downloadpaludis-3c79509ed74583db28b106b772b463f2d5d28dba.tar.gz
paludis-3c79509ed74583db28b106b772b463f2d5d28dba.tar.xz
Support foreign-endian ELF-files.
-rw-r--r--NEWS4
-rw-r--r--configure.ac4
-rw-r--r--src/clients/reconcilio/littlelf/elf.cc77
-rw-r--r--src/clients/reconcilio/littlelf/elf_dynamic_section.cc17
-rw-r--r--src/clients/reconcilio/littlelf/elf_dynamic_section.hh2
-rw-r--r--src/clients/reconcilio/littlelf/elf_relocation_section.cc34
-rw-r--r--src/clients/reconcilio/littlelf/elf_relocation_section.hh2
-rw-r--r--src/clients/reconcilio/littlelf/elf_sections.cc2
-rw-r--r--src/clients/reconcilio/littlelf/elf_sections.hh2
-rw-r--r--src/clients/reconcilio/littlelf/elf_symbol_section.cc25
-rw-r--r--src/clients/reconcilio/littlelf/elf_symbol_section.hh2
-rw-r--r--src/clients/reconcilio/util/Makefile.am12
-rw-r--r--src/clients/reconcilio/util/byte_swap.hh74
-rw-r--r--src/clients/reconcilio/util/byte_swap_TEST.cc78
14 files changed, 319 insertions, 16 deletions
diff --git a/NEWS b/NEWS
index 10a1d9b..d5e9024 100644
--- a/NEWS
+++ b/NEWS
@@ -12,7 +12,9 @@ trunk/:
* Paludis now fully supports filenames containing spaces.
- * Bug fixes: --dl-deps-default works again.
+ * Bug fixes: --dl-deps-default works again. More
+ robustness/compilance improvements for reconcilio, including
+ proper handling of ELF files that use the non-native byte order.
0.26.0_alpha2:
* STILL BROKEN, wait for 0.26.0 if you use these: CRAN, Ruby bindings for
diff --git a/configure.ac b/configure.ac
index 1a7fb82..6a9bda4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -66,6 +66,10 @@ dnl {{{ make pkg-config work... dumb macro...
PKG_PROG_PKG_CONFIG([0.9.0])
dnl }}}
+dnl {{{ check for byte order
+AC_C_BIGENDIAN
+dnl }}}
+
dnl {{{ check for partial specialisation of template classes
AC_MSG_CHECKING([for compiler support for partial specialisation of template classes])
AC_COMPILE_IFELSE([
diff --git a/src/clients/reconcilio/littlelf/elf.cc b/src/clients/reconcilio/littlelf/elf.cc
index cdcf7b6..aa5e803 100644
--- a/src/clients/reconcilio/littlelf/elf.cc
+++ b/src/clients/reconcilio/littlelf/elf.cc
@@ -1,10 +1,14 @@
+#include "config.h"
+
#include "elf.hh"
#include "elf_dynamic_section.hh"
#include "elf_relocation_section.hh"
#include "elf_symbol_section.hh"
#include "elf_types.hh"
+#include <src/clients/reconcilio/util/byte_swap.hh>
+
#include <paludis/util/iterator.hh>
#include <paludis/util/make_shared_ptr.hh>
#include <paludis/util/private_implementation_pattern-impl.hh>
@@ -29,8 +33,60 @@ namespace paludis
};
}
+enum {
+ native_byte_order =
+#if WORDS_BIGENDIAN
+ ELFDATA2MSB
+#else
+ ELFDATA2LSB
+#endif
+};
+
namespace
{
+ template <typename ElfType_>
+ struct ByteSwapElfHeader
+ {
+ static void swap_in_place(typename ElfType_::Header & hdr)
+ {
+ hdr.e_type = byte_swap(hdr.e_type);
+ hdr.e_machine = byte_swap(hdr.e_machine);
+ hdr.e_version = byte_swap(hdr.e_version);
+ hdr.e_entry = byte_swap(hdr.e_entry);
+ hdr.e_phoff = byte_swap(hdr.e_phoff);
+ hdr.e_shoff = byte_swap(hdr.e_shoff);
+ hdr.e_flags = byte_swap(hdr.e_flags);
+ hdr.e_ehsize = byte_swap(hdr.e_ehsize);
+ hdr.e_phentsize = byte_swap(hdr.e_phentsize);
+ hdr.e_phnum = byte_swap(hdr.e_phnum);
+ hdr.e_shentsize = byte_swap(hdr.e_shentsize);
+ hdr.e_shnum = byte_swap(hdr.e_shnum);
+ hdr.e_shstrndx = byte_swap(hdr.e_shstrndx);
+ }
+ };
+
+ template <typename ElfType_>
+ struct ByteSwapSectionHeader
+ {
+ static void swap_in_place(typename ElfType_::SectionHeader &);
+ };
+
+ template <typename ElfType_>
+ void
+ ByteSwapSectionHeader<ElfType_>::swap_in_place(typename ElfType_::SectionHeader & shdr)
+ {
+ shdr.sh_name = byte_swap(shdr.sh_name);
+ shdr.sh_type = byte_swap(shdr.sh_type);
+ shdr.sh_flags = byte_swap(shdr.sh_flags);
+ shdr.sh_addr = byte_swap(shdr.sh_addr);
+ shdr.sh_offset = byte_swap(shdr.sh_offset);
+ shdr.sh_size = byte_swap(shdr.sh_size);
+ shdr.sh_link = byte_swap(shdr.sh_link);
+ shdr.sh_info = byte_swap(shdr.sh_info);
+ shdr.sh_addralign = byte_swap(shdr.sh_addralign);
+ shdr.sh_entsize = byte_swap(shdr.sh_entsize);
+ }
+
class StreamExceptions
{
private:
@@ -181,6 +237,9 @@ ElfObject<ElfType_>::ElfObject(std::istream & stream) :
stream.seekg(0, std::ios::beg);
stream.read(reinterpret_cast<char *>(&_hdr), sizeof(typename ElfType_::Header));
+ bool need_byte_swap(_hdr.e_ident[EI_DATA] != native_byte_order);
+ if (need_byte_swap)
+ ByteSwapElfHeader<ElfType_>::swap_in_place(_hdr);
std::vector<typename ElfType_::SectionHeader> shdrs;
if (_hdr.e_shoff)
@@ -193,18 +252,26 @@ ElfObject<ElfType_>::ElfObject(std::istream & stream) :
{
std::vector<typename ElfType_::SectionHeader> my_shdrs(_hdr.e_shnum);
stream.read(reinterpret_cast<char *>(&my_shdrs.front()), sizeof(typename ElfType_::SectionHeader) * _hdr.e_shnum);
+ if (need_byte_swap)
+ std::for_each(my_shdrs.begin(), my_shdrs.end(),
+ &ByteSwapSectionHeader<ElfType_>::swap_in_place);
shdrs.swap(my_shdrs);
}
else
{
typename ElfType_::SectionHeader first_shdr;
stream.read(reinterpret_cast<char *>(&first_shdr), sizeof(typename ElfType_::SectionHeader));
+ if (need_byte_swap)
+ ByteSwapSectionHeader<ElfType_>::swap_in_place(first_shdr);
if (0 == first_shdr.sh_size)
throw InvalidElfFileError();
std::vector<typename ElfType_::SectionHeader> my_shdrs(first_shdr.sh_size);
my_shdrs[0] = first_shdr;
stream.read(reinterpret_cast<char *>(&my_shdrs[1]), sizeof(typename ElfType_::SectionHeader) * (first_shdr.sh_size - 1));
+ if (need_byte_swap)
+ std::for_each(next(my_shdrs.begin()), my_shdrs.end(),
+ &ByteSwapSectionHeader<ElfType_>::swap_in_place);
shdrs.swap(my_shdrs);
}
}
@@ -212,15 +279,15 @@ ElfObject<ElfType_>::ElfObject(std::istream & stream) :
for (typename std::vector<typename ElfType_::SectionHeader>::iterator i = shdrs.begin(); i != shdrs.end(); ++i)
{
if (i->sh_type == SHT_STRTAB)
- _imp->sections.push_back(make_shared_ptr(new StringSection<ElfType_>(*i, stream)));
+ _imp->sections.push_back(make_shared_ptr(new StringSection<ElfType_>(*i, stream, need_byte_swap)));
else if ( (i->sh_type == SHT_SYMTAB) || (i->sh_type == SHT_DYNSYM) )
- _imp->sections.push_back(make_shared_ptr(new SymbolSection<ElfType_>(*i, stream)));
+ _imp->sections.push_back(make_shared_ptr(new SymbolSection<ElfType_>(*i, stream, need_byte_swap)));
else if (i->sh_type == SHT_DYNAMIC)
- _imp->sections.push_back(make_shared_ptr(new DynamicSection<ElfType_>(*i, stream)));
+ _imp->sections.push_back(make_shared_ptr(new DynamicSection<ElfType_>(*i, stream, need_byte_swap)));
else if (i->sh_type == SHT_REL)
- _imp->sections.push_back(make_shared_ptr(new RelocationSection<ElfType_, Relocation<ElfType_> >(*i, stream)));
+ _imp->sections.push_back(make_shared_ptr(new RelocationSection<ElfType_, Relocation<ElfType_> >(*i, stream, need_byte_swap)));
else if (i->sh_type == SHT_RELA)
- _imp->sections.push_back(make_shared_ptr(new RelocationSection<ElfType_, RelocationA<ElfType_> >(*i, stream)));
+ _imp->sections.push_back(make_shared_ptr(new RelocationSection<ElfType_, RelocationA<ElfType_> >(*i, stream, need_byte_swap)));
else
_imp->sections.push_back(make_shared_ptr(new GenericSection<ElfType_>(*i)));
}
diff --git a/src/clients/reconcilio/littlelf/elf_dynamic_section.cc b/src/clients/reconcilio/littlelf/elf_dynamic_section.cc
index 293f508..a6856cb 100644
--- a/src/clients/reconcilio/littlelf/elf_dynamic_section.cc
+++ b/src/clients/reconcilio/littlelf/elf_dynamic_section.cc
@@ -3,6 +3,8 @@
#include "elf_types.hh"
#include "elf.hh"
+#include <src/clients/reconcilio/util/byte_swap.hh>
+
#include <paludis/util/clone-impl.hh>
#include <paludis/util/instantiation_policy-impl.hh>
#include <paludis/util/iterator.hh>
@@ -68,6 +70,16 @@ namespace littlelf_internals
namespace
{
template <typename ElfType_>
+ struct ByteSwapDynamicEntry
+ {
+ static void swap_in_place(typename ElfType_::DynamicEntry & entry)
+ {
+ entry.d_tag = byte_swap(entry.d_tag);
+ entry.d_un.d_val = byte_swap(entry.d_un.d_val);
+ }
+ };
+
+ template <typename ElfType_>
class DynamicSectionStringResolvingVisitor :
public SectionVisitor<ElfType_>
{
@@ -238,7 +250,7 @@ DynamicEntries<ElfType_>::has_entry(typename ElfType_::DynamicTag identifier) co
}
template <typename ElfType_>
-DynamicSection<ElfType_>::DynamicSection(const typename ElfType_::SectionHeader & shdr, std::istream & stream) :
+DynamicSection<ElfType_>::DynamicSection(const typename ElfType_::SectionHeader & shdr, std::istream & stream, bool need_byte_swap) :
Section<ElfType_>(shdr),
PrivateImplementationPattern<DynamicSection>(new Implementation<DynamicSection>)
{
@@ -248,6 +260,9 @@ DynamicSection<ElfType_>::DynamicSection(const typename ElfType_::SectionHeader
stream.seekg(shdr.sh_offset, std::ios::beg);
std::vector<typename ElfType_::DynamicEntry> tmp_entries(shdr.sh_size / sizeof(typename ElfType_::DynamicEntry));
stream.read( reinterpret_cast<char *>(&tmp_entries.front()), shdr.sh_size );
+ if (need_byte_swap)
+ std::for_each(tmp_entries.begin(), tmp_entries.end(),
+ &ByteSwapDynamicEntry<ElfType_>::swap_in_place);
for (typename std::vector<typename ElfType_::DynamicEntry>::iterator i = tmp_entries.begin(); i != tmp_entries.end(); ++i)
{
diff --git a/src/clients/reconcilio/littlelf/elf_dynamic_section.hh b/src/clients/reconcilio/littlelf/elf_dynamic_section.hh
index 7f25121..5edc08f 100644
--- a/src/clients/reconcilio/littlelf/elf_dynamic_section.hh
+++ b/src/clients/reconcilio/littlelf/elf_dynamic_section.hh
@@ -195,7 +195,7 @@ class DynamicSection :
using paludis::PrivateImplementationPattern<DynamicSection>::_imp;
public:
- DynamicSection(const typename ElfType_::SectionHeader &, std::istream &);
+ DynamicSection(const typename ElfType_::SectionHeader &, std::istream &, bool);
virtual ~DynamicSection();
virtual std::string get_type() const;
diff --git a/src/clients/reconcilio/littlelf/elf_relocation_section.cc b/src/clients/reconcilio/littlelf/elf_relocation_section.cc
index 5a3250d..3fdef06 100644
--- a/src/clients/reconcilio/littlelf/elf_relocation_section.cc
+++ b/src/clients/reconcilio/littlelf/elf_relocation_section.cc
@@ -3,6 +3,8 @@
#include "elf_types.hh"
#include "elf.hh"
+#include <src/clients/reconcilio/util/byte_swap.hh>
+
#include <paludis/util/private_implementation_pattern-impl.hh>
#include <paludis/util/visitor-impl.hh>
@@ -22,6 +24,32 @@ namespace paludis
};
}
+namespace
+{
+ template <typename, typename> struct ByteSwapRelocation;
+
+ template <typename ElfType_>
+ struct ByteSwapRelocation<ElfType_, Relocation<ElfType_> >
+ {
+ static void swap_in_place(typename ElfType_::Relocation & rel)
+ {
+ rel.r_offset = byte_swap(rel.r_offset);
+ rel.r_info = byte_swap(rel.r_info);
+ }
+ };
+
+ template <typename ElfType_>
+ struct ByteSwapRelocation<ElfType_, RelocationA<ElfType_> >
+ {
+ static void swap_in_place(typename ElfType_::RelocationA & rela)
+ {
+ rela.r_offset = byte_swap(rela.r_offset);
+ rela.r_info = byte_swap(rela.r_info);
+ rela.r_addend = byte_swap(rela.r_addend);
+ }
+ };
+}
+
template <typename ElfType_>
RelocationEntry<ElfType_>::RelocationEntry(const typename ElfType_::Relocation & my_relocation) :
_my_relocation(my_relocation)
@@ -48,7 +76,8 @@ template <typename ElfType_> const std::string Relocation<ElfType_>::type_name =
template <typename ElfType_> const std::string RelocationA<ElfType_>::type_name = "RELA";
template <typename ElfType_, typename Relocation_>
-RelocationSection<ElfType_, Relocation_>::RelocationSection(const typename ElfType_::SectionHeader & shdr, std::istream & stream) :
+RelocationSection<ElfType_, Relocation_>::RelocationSection(
+ const typename ElfType_::SectionHeader & shdr, std::istream & stream, bool need_byte_swap) :
Section<ElfType_>(shdr),
PrivateImplementationPattern<RelocationSection>(new Implementation<RelocationSection>)
{
@@ -58,6 +87,9 @@ RelocationSection<ElfType_, Relocation_>::RelocationSection(const typename ElfTy
std::vector<typename Relocation_::Type> relocations(shdr.sh_size / sizeof(typename Relocation_::Type));
stream.seekg(shdr.sh_offset, std::ios::beg);
stream.read(reinterpret_cast<char *>(&relocations.front()), shdr.sh_size);
+ if (need_byte_swap)
+ std::for_each(relocations.begin(), relocations.end(),
+ &ByteSwapRelocation<ElfType_, Relocation_>::swap_in_place);
for (typename std::vector<typename Relocation_::Type>::iterator i = relocations.begin(); i != relocations.end(); ++i)
_imp->relocations.push_back(typename Relocation_::Entry(*i));
diff --git a/src/clients/reconcilio/littlelf/elf_relocation_section.hh b/src/clients/reconcilio/littlelf/elf_relocation_section.hh
index 9e12417..4fdfb84 100644
--- a/src/clients/reconcilio/littlelf/elf_relocation_section.hh
+++ b/src/clients/reconcilio/littlelf/elf_relocation_section.hh
@@ -79,7 +79,7 @@ class RelocationSection :
using paludis::PrivateImplementationPattern<RelocationSection>::_imp;
public:
- RelocationSection(const typename ElfType_::SectionHeader &, std::istream &);
+ RelocationSection(const typename ElfType_::SectionHeader &, std::istream &, bool);
virtual ~RelocationSection();
virtual std::string get_type() const
diff --git a/src/clients/reconcilio/littlelf/elf_sections.cc b/src/clients/reconcilio/littlelf/elf_sections.cc
index 5e00621..a92454b 100644
--- a/src/clients/reconcilio/littlelf/elf_sections.cc
+++ b/src/clients/reconcilio/littlelf/elf_sections.cc
@@ -41,7 +41,7 @@ GenericSection<ElfType_>::get_type() const
}
template <typename ElfType_>
-StringSection<ElfType_>::StringSection(const typename ElfType_::SectionHeader & shdr, std::istream & stream) :
+StringSection<ElfType_>::StringSection(const typename ElfType_::SectionHeader & shdr, std::istream & stream, bool) :
Section<ElfType_>(shdr),
_stringTable(shdr.sh_size, ' ')
{
diff --git a/src/clients/reconcilio/littlelf/elf_sections.hh b/src/clients/reconcilio/littlelf/elf_sections.hh
index 3d5f69b..823a597 100644
--- a/src/clients/reconcilio/littlelf/elf_sections.hh
+++ b/src/clients/reconcilio/littlelf/elf_sections.hh
@@ -136,7 +136,7 @@ class StringSection :
std::string _stringTable;
public:
- StringSection(const typename ElfType_::SectionHeader &, std::istream &);
+ StringSection(const typename ElfType_::SectionHeader &, std::istream &, bool);
virtual ~StringSection();
std::string get_string(typename ElfType_::Word) const;
diff --git a/src/clients/reconcilio/littlelf/elf_symbol_section.cc b/src/clients/reconcilio/littlelf/elf_symbol_section.cc
index 6ddcab0..2665665 100644
--- a/src/clients/reconcilio/littlelf/elf_symbol_section.cc
+++ b/src/clients/reconcilio/littlelf/elf_symbol_section.cc
@@ -3,6 +3,8 @@
#include "elf_types.hh"
#include "elf.hh"
+#include <src/clients/reconcilio/util/byte_swap.hh>
+
#include <paludis/util/private_implementation_pattern-impl.hh>
#include <paludis/util/visitor-impl.hh>
@@ -23,6 +25,23 @@ namespace paludis
};
}
+namespace
+{
+ template <typename ElfType_>
+ struct ByteSwapSymbol
+ {
+ static void swap_in_place(typename ElfType_::Symbol & sym)
+ {
+ sym.st_name = byte_swap(sym.st_name);
+ sym.st_value = byte_swap(sym.st_value);
+ sym.st_size = byte_swap(sym.st_size);
+ sym.st_info = byte_swap(sym.st_info);
+ sym.st_other = byte_swap(sym.st_other);
+ sym.st_shndx = byte_swap(sym.st_shndx);
+ }
+ };
+}
+
namespace littlelf_internals
{
template <typename ElfType_>
@@ -114,7 +133,7 @@ Symbol<ElfType_>::~Symbol()
}
template <typename ElfType_>
-SymbolSection<ElfType_>::SymbolSection(const typename ElfType_::SectionHeader & shdr, std::istream & stream) :
+SymbolSection<ElfType_>::SymbolSection(const typename ElfType_::SectionHeader & shdr, std::istream & stream, bool need_byte_swap) :
Section<ElfType_>(shdr),
PrivateImplementationPattern<SymbolSection>(new Implementation<SymbolSection>),
_type("invalid")
@@ -129,6 +148,10 @@ SymbolSection<ElfType_>::SymbolSection(const typename ElfType_::SectionHeader &
std::vector<typename ElfType_::Symbol> symbols(shdr.sh_size / sizeof(typename ElfType_::Symbol));
stream.seekg(shdr.sh_offset, std::ios::beg);
stream.read( reinterpret_cast<char *>(&symbols.front()), shdr.sh_size );
+ if (need_byte_swap)
+ std::for_each(symbols.begin(), symbols.end(),
+ &ByteSwapSymbol<ElfType_>::swap_in_place);
+
for (typename std::vector<typename ElfType_::Symbol>::iterator i = symbols.begin(); i != symbols.end(); ++i)
_imp->symbols.push_back(Symbol<ElfType_>(*i));
}
diff --git a/src/clients/reconcilio/littlelf/elf_symbol_section.hh b/src/clients/reconcilio/littlelf/elf_symbol_section.hh
index 60d08af..8dcb132 100644
--- a/src/clients/reconcilio/littlelf/elf_symbol_section.hh
+++ b/src/clients/reconcilio/littlelf/elf_symbol_section.hh
@@ -67,7 +67,7 @@ class SymbolSection :
std::string _type;
public:
- SymbolSection(const typename ElfType_::SectionHeader &, std::istream &);
+ SymbolSection(const typename ElfType_::SectionHeader &, std::istream &, bool);
virtual ~SymbolSection();
virtual std::string get_type() const
diff --git a/src/clients/reconcilio/util/Makefile.am b/src/clients/reconcilio/util/Makefile.am
index 9735544..64f3a23 100644
--- a/src/clients/reconcilio/util/Makefile.am
+++ b/src/clients/reconcilio/util/Makefile.am
@@ -6,14 +6,15 @@ noinst_LIBRARIES = libreconcilioutil.a
libreconcilioutil_a_SOURCES = \
realpath.cc realpath.hh \
- wildcard_expander.cc wildcard_expander.hh
+ wildcard_expander.cc wildcard_expander.hh \
+ byte_swap.hh
TESTS_ENVIRONMENT = env \
TEST_SCRIPT_DIR="$(srcdir)/" \
TEST_OUTPUT_WRAPPER="`$(top_srcdir)/paludis/repositories/e/ebuild/utils/canonicalise $(top_builddir)/paludis/util/outputwrapper`" \
bash $(top_srcdir)/test/run_test.sh bash
-TESTS = realpath_TEST wildcard_expander_TEST
+TESTS = realpath_TEST wildcard_expander_TEST byte_swap_TEST
check_PROGRAMS = $(TESTS)
EXTRA_DIST = \
@@ -34,6 +35,13 @@ wildcard_expander_TEST_LDADD = \
$(top_builddir)/paludis/util/test_extras.o \
$(top_builddir)/test/libtest.a
+byte_swap_TEST_SOURCES = byte_swap_TEST.cc
+byte_swap_TEST_LDADD = \
+ libreconcilioutil.a \
+ $(top_builddir)/paludis/util/libpaludisutil.la \
+ $(top_builddir)/paludis/util/test_extras.o \
+ $(top_builddir)/test/libtest.a
+
CLEANFILES = *~ gmon.out *.gcov *.gcno *.gcda
MAINTAINERCLEANFILES = Makefile.in
diff --git a/src/clients/reconcilio/util/byte_swap.hh b/src/clients/reconcilio/util/byte_swap.hh
new file mode 100644
index 0000000..5a359dd
--- /dev/null
+++ b/src/clients/reconcilio/util/byte_swap.hh
@@ -0,0 +1,74 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 David Leverton
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_RECONCILIO_UTIL_BYTE_SWAP_HH
+#define PALUDIS_GUARD_RECONCILIO_UTIL_BYTE_SWAP_HH
+
+#include <cstddef>
+
+template <std::size_t, typename> struct ByteSwap;
+
+template <typename T_>
+struct ByteSwap<1, T_>
+{
+ static T_ swap(T_ x)
+ {
+ return x;
+ }
+};
+
+template <typename T_>
+struct ByteSwap<2, T_>
+{
+ static T_ swap(T_ x)
+ {
+ return ((x << 8) & (T_(0xFF) << 8)) | ((x >> 8) & T_(0xFF));
+ }
+};
+
+template <typename T_>
+struct ByteSwap<4, T_>
+{
+ static T_ swap(T_ x)
+ {
+ return ((x << 24) & (T_(0xFF) << 24)) | ((x << 8) & (T_(0xFF) << 16))
+ | ((x >> 8) & (T_(0xFF) << 8)) | ((x >> 24) & T_(0xFF) );
+ }
+};
+
+template <typename T_>
+struct ByteSwap<8, T_>
+{
+ static T_ swap(T_ x)
+ {
+ return ((x << 56) & (T_(0xFF) << 56)) | ((x << 40) & (T_(0xFF) << 48))
+ | ((x << 24) & (T_(0xFF) << 40)) | ((x << 8) & (T_(0xFF) << 32))
+ | ((x >> 8) & (T_(0xFF) << 24)) | ((x >> 24) & (T_(0xFF) << 16))
+ | ((x >> 40) & (T_(0xFF) << 8)) | ((x >> 56) & T_(0xFF) );
+ }
+};
+
+template <typename T_>
+inline T_
+byte_swap(T_ x)
+{
+ return ByteSwap<sizeof(T_), T_>::swap(x);
+}
+
+#endif
diff --git a/src/clients/reconcilio/util/byte_swap_TEST.cc b/src/clients/reconcilio/util/byte_swap_TEST.cc
new file mode 100644
index 0000000..aad78b9
--- /dev/null
+++ b/src/clients/reconcilio/util/byte_swap_TEST.cc
@@ -0,0 +1,78 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 David Leverton
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "byte_swap.hh"
+
+#include <test/test_runner.hh>
+#include <test/test_framework.hh>
+
+#include <stdint.h>
+
+using namespace test;
+using namespace paludis;
+
+namespace test_cases
+{
+ struct ByteSwapTest : TestCase
+ {
+ ByteSwapTest() : TestCase("byte_swap") {}
+
+ int64_t int64(int64_t a, int64_t b)
+ {
+ return (a << 32) | b;
+ }
+
+ uint64_t uint64(uint64_t a, uint64_t b)
+ {
+ return (a << 32) | b;
+ }
+
+#define CHECK(T, X, Y) do { TEST_CHECK_EQUAL(byte_swap(T(X)), T(Y)); TEST_CHECK_EQUAL(byte_swap(T(Y)), T(X)); } while (0)
+
+ void run()
+ {
+ CHECK(int8_t, 0x42, 0x42);
+ CHECK(uint8_t, 0x42, 0x42);
+ CHECK(int8_t, 0x92, 0x92);
+ CHECK(uint8_t, 0x92, 0x92);
+
+ CHECK(int16_t, 0x4218, 0x1842);
+ CHECK(uint16_t, 0x4218, 0x1842);
+ CHECK(int16_t, 0x4298, 0x9842);
+ CHECK(uint16_t, 0x4298, 0x9842);
+ CHECK(int16_t, 0x9218, 0x1892);
+ CHECK(uint16_t, 0x9218, 0x1892);
+
+ CHECK(int32_t, 0x4218A43F, 0x3FA41842);
+ CHECK(uint32_t, 0x4218A43F, 0x3FA41842);
+ CHECK(int32_t, 0x4218A4CF, 0xCFA41842);
+ CHECK(uint32_t, 0x4218A4CF, 0xCFA41842);
+ CHECK(int32_t, 0x9218A43F, 0x3FA41892);
+ CHECK(uint32_t, 0x9218A43F, 0x3FA41892);
+
+ CHECK(int64_t, int64(0x42A57104, 0x32D61259), int64(0x5912D632, 0x0471A542));
+ CHECK(uint64_t, uint64(0x42A57104, 0x32D61259), uint64(0x5912D632, 0x0471A542));
+ CHECK(int64_t, int64(0x42A57104, 0x32D612E9), int64(0xE912D632, 0x0471A542));
+ CHECK(uint64_t, uint64(0x42A57104, 0x32D612E9), uint64(0xE912D632, 0x0471A542));
+ CHECK(int64_t, int64(0x92A57104, 0x32D61259), int64(0x5912D632, 0x0471A592));
+ CHECK(uint64_t, uint64(0x92A57104, 0x32D61259), uint64(0x5912D632, 0x0471A592));
+ }
+ } byte_swap_test;
+}
+