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"