Add a SectionOffsetAddress class.

Pdb files contain address represented as segment/offset
pairs. This CL introduces a class to encapsulate this
concept.

It has the same interface as AddressImpl, except for the
operator- that accepts another address of the same type.
The class is a lightweight wrapper for 2 integers, which
can be freely copied.

BUG=
R=chrisha@chromium.org

Review URL: https://codereview.appspot.com/114610045

git-svn-id: http://sawbuck.googlecode.com/svn/trunk@2224 15e8cca8-e42c-11de-a347-f34a4f72eb7d
diff --git a/syzygy/core/core.gyp b/syzygy/core/core.gyp
index 9b10062..d48556e 100644
--- a/syzygy/core/core.gyp
+++ b/syzygy/core/core.gyp
@@ -43,6 +43,8 @@
         'register_internal.h',
         'register.cc',
         'register.h',
+        'section_offset_address.cc',
+        'section_offset_address.h',
         'serialization.cc',
         'serialization.h',
         'serialization_impl.h',
@@ -86,6 +88,7 @@
         'file_util_unittest.cc',
         'json_file_writer_unittest.cc',
         'register_unittest.cc',
+        'section_offset_address_unittest.cc',
         'serialization_unittest.cc',
         'string_table_unittest.cc',
         'unittest_util_unittest.cc',
diff --git a/syzygy/core/section_offset_address.cc b/syzygy/core/section_offset_address.cc
new file mode 100644
index 0000000..ef392a5
--- /dev/null
+++ b/syzygy/core/section_offset_address.cc
@@ -0,0 +1,188 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "syzygy/core/section_offset_address.h"
+
+#include <iostream>
+#include "base/logging.h"
+#include "base/stringprintf.h"
+#include "syzygy/common/align.h"
+
+namespace core {
+
+namespace {
+
+// The minimum alignment of a PE section.
+// See http://msdn.microsoft.com/library/windows/desktop/ms680339.aspx
+const uint32 kPESectionMinAlignment = 512;
+
+// Host function for compile asserts.
+void SectionOffsetAddressCompileAsserts() {
+  COMPILE_ASSERT(sizeof(SectionOffsetAddress) == 2 * sizeof(uint32),
+                 section_offset_address_must_be_8_bytes);
+}
+
+}  // namespace
+
+const SectionOffsetAddress SectionOffsetAddress::kInvalidAddress(~0U, ~0U);
+
+SectionOffsetAddress::SectionOffset::SectionOffset(
+    uint32 section_id, uint32 offset)
+    : section_id(section_id),
+      offset(offset) {
+}
+
+bool SectionOffsetAddress::SectionOffset::operator<(
+    const SectionOffset& other) const {
+  if (section_id < other.section_id)
+    return true;
+  if (section_id > other.section_id)
+    return false;
+  return offset < other.offset;
+}
+
+bool SectionOffsetAddress::SectionOffset::operator<=(
+    const SectionOffset& other) const {
+  if (section_id < other.section_id)
+    return true;
+  if (section_id > other.section_id)
+    return false;
+  return offset <= other.offset;
+}
+
+bool SectionOffsetAddress::SectionOffset::operator>(
+    const SectionOffset& other) const {
+  if (section_id > other.section_id)
+    return true;
+  if (section_id < other.section_id)
+    return false;
+  return offset > other.offset;
+}
+
+bool SectionOffsetAddress::SectionOffset::operator>=(
+    const SectionOffset& other) const {
+  if (section_id > other.section_id)
+    return true;
+  if (section_id < other.section_id)
+    return false;
+  return offset >= other.offset;
+}
+
+bool SectionOffsetAddress::SectionOffset::operator==(
+    const SectionOffset& other) const {
+  return section_id == other.section_id && offset == other.offset;
+}
+
+bool SectionOffsetAddress::SectionOffset::operator!=(
+    const SectionOffset& other) const {
+  return section_id != other.section_id || offset != other.offset;
+}
+
+SectionOffsetAddress::SectionOffsetAddress() : value_(0, 0) {
+}
+
+SectionOffsetAddress::SectionOffsetAddress(uint32 section_id, uint32 offset)
+    : value_(section_id, offset) {
+}
+
+SectionOffsetAddress::SectionOffsetAddress(const SectionOffsetAddress& other)
+    : value_(other.value_) {
+}
+
+bool SectionOffsetAddress::operator<(const SectionOffsetAddress& other) const {
+  return value_ < other.value_;
+}
+
+bool SectionOffsetAddress::operator<=(const SectionOffsetAddress& other) const {
+  return value_ <= other.value_;
+}
+
+bool SectionOffsetAddress::operator>(const SectionOffsetAddress& other) const {
+  return value_ > other.value_;
+}
+
+bool SectionOffsetAddress::operator>=(const SectionOffsetAddress& other) const {
+  return value_ >= other.value_;
+}
+
+bool SectionOffsetAddress::operator==(const SectionOffsetAddress& other) const {
+  return value_ == other.value_;
+}
+
+bool SectionOffsetAddress::operator!=(const SectionOffsetAddress& other) const {
+  return value_ != other.value_;
+}
+
+void SectionOffsetAddress::operator=(const SectionOffsetAddress& other) {
+  value_ = other.value_;
+}
+
+void SectionOffsetAddress::operator+=(int32 offset) {
+  value_.offset += offset;
+}
+
+void SectionOffsetAddress::operator-=(int32 offset) {
+  value_.offset -= offset;
+}
+
+SectionOffsetAddress SectionOffsetAddress::operator+(size_t offset) const {
+  return SectionOffsetAddress(section_id(), value_.offset + offset);
+}
+
+SectionOffsetAddress SectionOffsetAddress::operator-(size_t offset) const {
+  return SectionOffsetAddress(section_id(), value_.offset - offset);
+}
+
+SectionOffsetAddress SectionOffsetAddress::AlignUp(size_t alignment) const {
+  DCHECK_NE(0U, alignment);
+  // Sections are aligned on a power of 2 greater or equal to 512
+  // (see http://msdn.microsoft.com/library/windows/desktop/ms680339.aspx).
+  // Without knowing the exact alignment of the section, it is impossible to
+  // guarantee an alignment on a power of 2 greater than 512.
+  DCHECK_LE(alignment, kPESectionMinAlignment);
+
+  return SectionOffsetAddress(
+      section_id(), common::AlignUp(offset(), alignment));
+}
+
+bool SectionOffsetAddress::IsAligned(size_t alignment) const {
+  DCHECK_NE(0U, alignment);
+  DCHECK_LE(alignment, kPESectionMinAlignment);
+
+  return common::IsAligned(offset(), alignment);
+}
+
+uint32 SectionOffsetAddress::GetAlignment() const {
+  uint32 alignment = common::GetAlignment(offset());
+  if (alignment > kPESectionMinAlignment)
+    return kPESectionMinAlignment;
+  return alignment;
+}
+
+bool SectionOffsetAddress::Save(OutArchive *out_archive) const {
+  return out_archive->Save(section_id()) && out_archive->Save(offset());
+}
+
+bool SectionOffsetAddress::Load(InArchive *in_archive) {
+  return in_archive->Load(&value_.section_id) &&
+      in_archive->Load(&value_.offset);
+}
+
+std::ostream& operator<<(std::ostream& str, const SectionOffsetAddress& addr) {
+  str << base::StringPrintf(
+      "SectionOffset(0x%08X, 0x%08X)", addr.section_id(), addr.offset());
+  return str;
+}
+
+}  // namespace core
diff --git a/syzygy/core/section_offset_address.h b/syzygy/core/section_offset_address.h
new file mode 100644
index 0000000..8fa41f0
--- /dev/null
+++ b/syzygy/core/section_offset_address.h
@@ -0,0 +1,108 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SYZYGY_CORE_SECTION_OFFSET_ADDRESS_H_
+#define SYZYGY_CORE_SECTION_OFFSET_ADDRESS_H_
+
+#include <iosfwd>
+#include "base/basictypes.h"
+#include "syzygy/core/serialization.h"
+
+namespace core {
+
+// This class implements an address in a PE image file represented as a section
+// index and an offset in the section. It has the same interface as AddressImpl,
+// except for the operator- that accepts another address of the same type.
+// The class is a lightweight wrapper for 2 integers, which can be freely
+// copied.
+class SectionOffsetAddress {
+ public:
+  static const SectionOffsetAddress kInvalidAddress;
+
+  // A struct that contains all data from a SectionOffsetAddress and that is
+  // returned by value().
+  struct SectionOffset {
+    SectionOffset(uint32 section_id, uint32 offset);
+
+    bool operator<(const SectionOffset& other) const;
+    bool operator<=(const SectionOffset& other) const;
+    bool operator>(const SectionOffset& other) const;
+    bool operator>=(const SectionOffset& other) const;
+    bool operator==(const SectionOffset& other) const;
+    bool operator!=(const SectionOffset& other) const;
+
+    uint32 section_id;
+    uint32 offset;
+  };
+
+  SectionOffsetAddress();
+  SectionOffsetAddress(uint32 section_id, uint32 offset);
+
+  // Non-explicit copy constructor, for STL container compatibility.
+  SectionOffsetAddress(const SectionOffsetAddress& other);  // NOLINT
+
+  bool operator<(const SectionOffsetAddress& other) const;
+  bool operator<=(const SectionOffsetAddress& other) const;
+  bool operator>(const SectionOffsetAddress& other) const;
+  bool operator>=(const SectionOffsetAddress& other) const;
+  bool operator==(const SectionOffsetAddress& other) const;
+  bool operator!=(const SectionOffsetAddress& other) const;
+
+  void operator=(const SectionOffsetAddress& other);
+  void operator+=(int32 offset);
+  void operator-=(int32 offset);
+
+  SectionOffsetAddress operator+(size_t offset) const;
+  SectionOffsetAddress operator-(size_t offset) const;
+
+  const SectionOffset& value() const { return value_; }
+  void set_value(const SectionOffset& value) { value_ = value; }
+
+  uint32 section_id() const { return value_.section_id; }
+  void set_section_id(uint32 section_id) { value_.section_id = section_id; }
+
+  uint32 offset() const { return value_.offset; }
+  void set_offset(uint32 offset) { value_.offset = offset; }
+
+  // Aligns the address on a multiple of |alignment|.
+  // @param alignment the alignment boundary to round the address up to.
+  // @pre alignment != 0 && alignment <= 512.
+  // @returns the aligned address.
+  SectionOffsetAddress AlignUp(size_t alignment) const;
+
+  // @param alignment The alignment boundary to test.
+  // @pre alignment != 0 && alignment <= 512.
+  // @returns true iff value is an even multiple of alignment.
+  bool IsAligned(size_t alignment) const;
+
+  // Determines the address alignment by counting the trailing zeros.
+  // The returned value will be at most 512 because it is impossible to
+  // guarantee an alignment on a greater power of 2 without knowing the
+  // exact alignment of the section.
+  // @returns the alignment of the address.
+  uint32 GetAlignment() const;
+
+  // For serialization.
+  bool Save(OutArchive *out_archive) const;
+  bool Load(InArchive *in_archive);
+
+ private:
+  SectionOffset value_;
+};
+
+std::ostream& operator<<(std::ostream& str, const SectionOffsetAddress& addr);
+
+}  // namespace core
+
+#endif  // SYZYGY_CORE_SECTION_OFFSET_ADDRESS_H_
diff --git a/syzygy/core/section_offset_address_unittest.cc b/syzygy/core/section_offset_address_unittest.cc
new file mode 100644
index 0000000..c21e6cd
--- /dev/null
+++ b/syzygy/core/section_offset_address_unittest.cc
@@ -0,0 +1,200 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "syzygy/core/section_offset_address.h"
+
+#include "gtest/gtest.h"
+#include "syzygy/core/unittest_util.h"
+
+namespace core {
+
+namespace {
+
+const uint32 kSectionId = 2;
+const uint32 kOffset = 0xCAFEBABE;
+
+}  // namespace
+
+TEST(SectionOffsetAddressTest, DefaultInitialization) {
+  SectionOffsetAddress address;
+  EXPECT_EQ(0, address.section_id());
+  EXPECT_EQ(0, address.offset());
+}
+
+TEST(SectionOffsetAddressTest, CreateInitialialized) {
+  const uint32 kSectionId = 2;
+  const uint32 kOffset = 0xCAFEBABE;
+
+  SectionOffsetAddress address(kSectionId, kOffset);
+
+  EXPECT_EQ(kSectionId, address.section_id());
+  EXPECT_EQ(kOffset, address.offset());
+}
+
+TEST(SectionOffsetAddressTest, ValueComparison) {
+  const SectionOffsetAddress::SectionOffset kOne(1, 0);
+  const SectionOffsetAddress::SectionOffset kTwo(1, 10);
+  const SectionOffsetAddress::SectionOffset kThree(2, 0);
+
+  EXPECT_TRUE(kOne < kTwo);
+  EXPECT_FALSE(kOne < kOne);
+  EXPECT_FALSE(kTwo < kOne);
+  EXPECT_TRUE(kTwo < kThree);
+  EXPECT_FALSE(kThree < kOne);
+  EXPECT_FALSE(kThree < kTwo);
+
+  EXPECT_TRUE(kOne <= kTwo);
+  EXPECT_TRUE(kOne <= kOne);
+  EXPECT_FALSE(kTwo <= kOne);
+  EXPECT_TRUE(kTwo <= kThree);
+  EXPECT_FALSE(kThree <= kOne);
+  EXPECT_FALSE(kThree <= kTwo);
+
+  EXPECT_FALSE(kOne > kTwo);
+  EXPECT_FALSE(kOne > kOne);
+  EXPECT_TRUE(kTwo > kOne);
+  EXPECT_FALSE(kTwo > kThree);
+  EXPECT_TRUE(kThree > kOne);
+  EXPECT_TRUE(kThree > kTwo);
+
+  EXPECT_FALSE(kOne >= kTwo);
+  EXPECT_TRUE(kOne >= kOne);
+  EXPECT_TRUE(kTwo >= kOne);
+  EXPECT_FALSE(kTwo >= kThree);
+  EXPECT_TRUE(kThree >= kOne);
+  EXPECT_TRUE(kThree >= kTwo);
+
+  const SectionOffsetAddress::SectionOffset kOtherOne(1, 0);
+  EXPECT_TRUE(kOne == kOtherOne);
+  EXPECT_FALSE(kOne == kTwo);
+  EXPECT_FALSE(kOne != kOtherOne);
+  EXPECT_TRUE(kOne != kTwo);
+}
+
+TEST(SectionOffsetAddressTest, Operators) {
+  const SectionOffsetAddress kOne(1, 0);
+  const SectionOffsetAddress kTwo(1, 10);
+  const SectionOffsetAddress kThree(2, 0);
+
+  EXPECT_TRUE(kOne < kTwo);
+  EXPECT_FALSE(kOne < kOne);
+  EXPECT_FALSE(kTwo < kOne);
+  EXPECT_TRUE(kTwo < kThree);
+  EXPECT_FALSE(kThree < kOne);
+  EXPECT_FALSE(kThree < kTwo);
+
+  EXPECT_TRUE(kOne <= kTwo);
+  EXPECT_TRUE(kOne <= kOne);
+  EXPECT_FALSE(kTwo <= kOne);
+  EXPECT_TRUE(kTwo <= kThree);
+  EXPECT_FALSE(kThree <= kOne);
+  EXPECT_FALSE(kThree <= kTwo);
+
+  EXPECT_FALSE(kOne > kTwo);
+  EXPECT_FALSE(kOne > kOne);
+  EXPECT_TRUE(kTwo > kOne);
+  EXPECT_FALSE(kTwo > kThree);
+  EXPECT_TRUE(kThree > kOne);
+  EXPECT_TRUE(kThree > kTwo);
+
+  EXPECT_FALSE(kOne >= kTwo);
+  EXPECT_TRUE(kOne >= kOne);
+  EXPECT_TRUE(kTwo >= kOne);
+  EXPECT_FALSE(kTwo >= kThree);
+  EXPECT_TRUE(kThree >= kOne);
+  EXPECT_TRUE(kThree >= kTwo);
+
+  SectionOffsetAddress addr(kOne);
+  EXPECT_TRUE(kOne == addr);
+  EXPECT_FALSE(addr == kTwo);
+  EXPECT_FALSE(kOne != addr);
+  EXPECT_TRUE(addr != kTwo);
+  EXPECT_EQ(1, addr.section_id());
+  EXPECT_EQ(0, addr.offset());
+
+  EXPECT_TRUE(kOne + 10 == kTwo);
+  EXPECT_TRUE(kOne == kTwo - 10);
+
+  addr += 10;
+  EXPECT_TRUE(addr == kTwo);
+  addr -= 10;
+  EXPECT_TRUE(addr == kOne);
+
+  addr = kThree;
+  EXPECT_TRUE(addr == kThree);
+}
+
+TEST(SectionOffsetAddressTest, SetValue) {
+  SectionOffsetAddress address(0, 0);
+  address.set_value(SectionOffsetAddress::SectionOffset(kSectionId, kOffset));
+
+  EXPECT_EQ(kSectionId, address.value().section_id);
+  EXPECT_EQ(kOffset, address.value().offset);
+}
+
+TEST(SectionOffsetAddressTest, SetSectionId) {
+  SectionOffsetAddress address(0, 0);
+  address.set_section_id(kSectionId);
+  EXPECT_EQ(kSectionId, address.value().section_id);
+}
+
+TEST(SectionOffsetAddressTest, SetOffset) {
+  SectionOffsetAddress address(0, 0);
+  address.set_offset(kOffset);
+  EXPECT_EQ(kOffset, address.value().offset);
+}
+
+TEST(SectionOffsetAddressTest, AlignUp) {
+  const SectionOffsetAddress one(0, 1);
+  const SectionOffsetAddress two(0, 2);
+  const SectionOffsetAddress four(0, 4);
+  const SectionOffsetAddress eight(0, 8);
+  const SectionOffsetAddress sixteen(0, 16);
+
+  EXPECT_EQ(one.AlignUp(1), one);
+  EXPECT_EQ(one.AlignUp(2), two);
+  EXPECT_EQ(one.AlignUp(4), four);
+  EXPECT_EQ(one.AlignUp(8), eight);
+  EXPECT_EQ(one.AlignUp(16), sixteen);
+
+  EXPECT_TRUE(one.AlignUp(1).IsAligned(1));
+  EXPECT_TRUE(one.AlignUp(2).IsAligned(2));
+  EXPECT_TRUE(one.AlignUp(4).IsAligned(4));
+  EXPECT_TRUE(one.AlignUp(8).IsAligned(8));
+  EXPECT_TRUE(one.AlignUp(16).IsAligned(16));
+}
+
+TEST(SectionOffsetAddressTest, GetAlignment) {
+  const uint32 max_alignment = 512;
+
+  const SectionOffsetAddress zero(0, 0);
+  EXPECT_EQ(max_alignment, zero.GetAlignment());
+  const SectionOffsetAddress one(0, 1);
+
+  for (uint32 i = 1; i <= max_alignment; i <<= 1) {
+    SectionOffsetAddress address(0, i);
+    EXPECT_EQ(i, address.GetAlignment());
+  }
+
+  SectionOffsetAddress big_offset(0, 1024);
+  EXPECT_EQ(max_alignment, big_offset.GetAlignment());
+}
+
+TEST(SectionOffsetAddressTest, Serialization) {
+  const SectionOffsetAddress address(5, 42);
+
+  EXPECT_TRUE(testing::TestSerialization(address));
+}
+
+}  // namespace core
diff --git a/syzygy/experimental/pdb_writer/symbol.h b/syzygy/experimental/pdb_writer/symbol.h
index 7e5e4fd..e32619c 100644
--- a/syzygy/experimental/pdb_writer/symbol.h
+++ b/syzygy/experimental/pdb_writer/symbol.h
@@ -14,7 +14,7 @@
 
 #ifndef SYZYGY_EXPERIMENTAL_PDB_WRITER_SYMBOL_H_
 #define SYZYGY_EXPERIMENTAL_PDB_WRITER_SYMBOL_H_
-

+
 #include <windows.h>
 
 #include "base/basictypes.h"