You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
297 lines
11 KiB
297 lines
11 KiB
// Copyright (c) 2010, 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.
|
|
//
|
|
// module_comparer.cc: ModuleComparer implementation.
|
|
// See module_comparer.h for documentation.
|
|
//
|
|
// Author: lambxsy@google.com (Siyang Xie)
|
|
|
|
#include "processor/module_comparer.h"
|
|
|
|
#include <map>
|
|
#include <string>
|
|
|
|
#include "processor/basic_code_module.h"
|
|
#include "processor/logging.h"
|
|
#include "processor/scoped_ptr.h"
|
|
|
|
#define ASSERT_TRUE(condition) \
|
|
if (!(condition)) { \
|
|
BPLOG(ERROR) << "FAIL: " << #condition << " @ " \
|
|
<< __FILE__ << ":" << __LINE__; \
|
|
return false; \
|
|
}
|
|
|
|
#define ASSERT_FALSE(condition) ASSERT_TRUE(!(condition))
|
|
|
|
namespace google_breakpad {
|
|
|
|
bool ModuleComparer::Compare(const string &symbol_data) {
|
|
scoped_ptr<BasicModule> basic_module(new BasicModule("test_module"));
|
|
scoped_ptr<FastModule> fast_module(new FastModule("test_module"));
|
|
|
|
// Load symbol data into basic_module
|
|
scoped_array<char> buffer(new char[symbol_data.size() + 1]);
|
|
strcpy(buffer.get(), symbol_data.c_str());
|
|
ASSERT_TRUE(basic_module->LoadMapFromMemory(buffer.get()));
|
|
buffer.reset();
|
|
|
|
// Serialize BasicSourceLineResolver::Module.
|
|
unsigned int serialized_size = 0;
|
|
scoped_array<char> serialized_data(
|
|
serializer_.Serialize(*(basic_module.get()), &serialized_size));
|
|
ASSERT_TRUE(serialized_data.get());
|
|
BPLOG(INFO) << "Serialized size = " << serialized_size << " Bytes";
|
|
|
|
// Load FastSourceLineResolver::Module using serialized data.
|
|
ASSERT_TRUE(fast_module->LoadMapFromMemory(serialized_data.get()));
|
|
|
|
// Compare FastSourceLineResolver::Module with
|
|
// BasicSourceLineResolver::Module.
|
|
ASSERT_TRUE(CompareModule(basic_module.get(), fast_module.get()));
|
|
|
|
return true;
|
|
}
|
|
|
|
// Traversal the content of module and do comparison
|
|
bool ModuleComparer::CompareModule(const BasicModule *basic_module,
|
|
const FastModule *fast_module) const {
|
|
// Compare name_.
|
|
ASSERT_TRUE(basic_module->name_ == fast_module->name_);
|
|
|
|
// Compare files_:
|
|
{
|
|
BasicModule::FileMap::const_iterator iter1 = basic_module->files_.begin();
|
|
FastModule::FileMap::iterator iter2 = fast_module->files_.begin();
|
|
while (iter1 != basic_module->files_.end()
|
|
&& iter2 != fast_module->files_.end()) {
|
|
ASSERT_TRUE(iter1->first == iter2.GetKey());
|
|
string tmp(iter2.GetValuePtr());
|
|
ASSERT_TRUE(iter1->second == tmp);
|
|
++iter1;
|
|
++iter2;
|
|
}
|
|
ASSERT_TRUE(iter1 == basic_module->files_.end());
|
|
ASSERT_TRUE(iter2 == fast_module->files_.end());
|
|
}
|
|
|
|
// Compare functions_:
|
|
{
|
|
RangeMap<MemAddr, linked_ptr<BasicFunc> >::MapConstIterator iter1;
|
|
StaticRangeMap<MemAddr, FastFunc>::MapConstIterator iter2;
|
|
iter1 = basic_module->functions_.map_.begin();
|
|
iter2 = fast_module->functions_.map_.begin();
|
|
while (iter1 != basic_module->functions_.map_.end()
|
|
&& iter2 != fast_module->functions_.map_.end()) {
|
|
ASSERT_TRUE(iter1->first == iter2.GetKey());
|
|
ASSERT_TRUE(iter1->second.base() == iter2.GetValuePtr()->base());
|
|
ASSERT_TRUE(CompareFunction(
|
|
iter1->second.entry().get(), iter2.GetValuePtr()->entryptr()));
|
|
++iter1;
|
|
++iter2;
|
|
}
|
|
ASSERT_TRUE(iter1 == basic_module->functions_.map_.end());
|
|
ASSERT_TRUE(iter2 == fast_module->functions_.map_.end());
|
|
}
|
|
|
|
// Compare public_symbols_:
|
|
{
|
|
AddressMap<MemAddr, linked_ptr<BasicPubSymbol> >::MapConstIterator iter1;
|
|
StaticAddressMap<MemAddr, FastPubSymbol>::MapConstIterator iter2;
|
|
iter1 = basic_module->public_symbols_.map_.begin();
|
|
iter2 = fast_module->public_symbols_.map_.begin();
|
|
while (iter1 != basic_module->public_symbols_.map_.end()
|
|
&& iter2 != fast_module->public_symbols_.map_.end()) {
|
|
ASSERT_TRUE(iter1->first == iter2.GetKey());
|
|
ASSERT_TRUE(ComparePubSymbol(
|
|
iter1->second.get(), iter2.GetValuePtr()));
|
|
++iter1;
|
|
++iter2;
|
|
}
|
|
ASSERT_TRUE(iter1 == basic_module->public_symbols_.map_.end());
|
|
ASSERT_TRUE(iter2 == fast_module->public_symbols_.map_.end());
|
|
}
|
|
|
|
// Compare windows_frame_info_[]:
|
|
for (int i = 0; i < WindowsFrameInfo::STACK_INFO_LAST; ++i) {
|
|
ASSERT_TRUE(CompareCRM(&(basic_module->windows_frame_info_[i]),
|
|
&(fast_module->windows_frame_info_[i])));
|
|
}
|
|
|
|
// Compare cfi_initial_rules_:
|
|
{
|
|
RangeMap<MemAddr, string>::MapConstIterator iter1;
|
|
StaticRangeMap<MemAddr, char>::MapConstIterator iter2;
|
|
iter1 = basic_module->cfi_initial_rules_.map_.begin();
|
|
iter2 = fast_module->cfi_initial_rules_.map_.begin();
|
|
while (iter1 != basic_module->cfi_initial_rules_.map_.end()
|
|
&& iter2 != fast_module->cfi_initial_rules_.map_.end()) {
|
|
ASSERT_TRUE(iter1->first == iter2.GetKey());
|
|
ASSERT_TRUE(iter1->second.base() == iter2.GetValuePtr()->base());
|
|
string tmp(iter2.GetValuePtr()->entryptr());
|
|
ASSERT_TRUE(iter1->second.entry() == tmp);
|
|
++iter1;
|
|
++iter2;
|
|
}
|
|
ASSERT_TRUE(iter1 == basic_module->cfi_initial_rules_.map_.end());
|
|
ASSERT_TRUE(iter2 == fast_module->cfi_initial_rules_.map_.end());
|
|
}
|
|
|
|
// Compare cfi_delta_rules_:
|
|
{
|
|
map<MemAddr, string>::const_iterator iter1;
|
|
StaticMap<MemAddr, char>::iterator iter2;
|
|
iter1 = basic_module->cfi_delta_rules_.begin();
|
|
iter2 = fast_module->cfi_delta_rules_.begin();
|
|
while (iter1 != basic_module->cfi_delta_rules_.end()
|
|
&& iter2 != fast_module->cfi_delta_rules_.end()) {
|
|
ASSERT_TRUE(iter1->first == iter2.GetKey());
|
|
string tmp(iter2.GetValuePtr());
|
|
ASSERT_TRUE(iter1->second == tmp);
|
|
++iter1;
|
|
++iter2;
|
|
}
|
|
ASSERT_TRUE(iter1 == basic_module->cfi_delta_rules_.end());
|
|
ASSERT_TRUE(iter2 == fast_module->cfi_delta_rules_.end());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ModuleComparer::CompareFunction(const BasicFunc *basic_func,
|
|
const FastFunc *fast_func_raw) const {
|
|
FastFunc* fast_func = new FastFunc();
|
|
fast_func->CopyFrom(fast_func_raw);
|
|
ASSERT_TRUE(basic_func->name == fast_func->name);
|
|
ASSERT_TRUE(basic_func->address == fast_func->address);
|
|
ASSERT_TRUE(basic_func->size == fast_func->size);
|
|
|
|
// compare range map of lines:
|
|
RangeMap<MemAddr, linked_ptr<BasicLine> >::MapConstIterator iter1;
|
|
StaticRangeMap<MemAddr, FastLine>::MapConstIterator iter2;
|
|
iter1 = basic_func->lines.map_.begin();
|
|
iter2 = fast_func->lines.map_.begin();
|
|
while (iter1 != basic_func->lines.map_.end()
|
|
&& iter2 != fast_func->lines.map_.end()) {
|
|
ASSERT_TRUE(iter1->first == iter2.GetKey());
|
|
ASSERT_TRUE(iter1->second.base() == iter2.GetValuePtr()->base());
|
|
ASSERT_TRUE(CompareLine(iter1->second.entry().get(),
|
|
iter2.GetValuePtr()->entryptr()));
|
|
++iter1;
|
|
++iter2;
|
|
}
|
|
ASSERT_TRUE(iter1 == basic_func->lines.map_.end());
|
|
ASSERT_TRUE(iter2 == fast_func->lines.map_.end());
|
|
|
|
delete fast_func;
|
|
return true;
|
|
}
|
|
|
|
bool ModuleComparer::CompareLine(const BasicLine *basic_line,
|
|
const FastLine *fast_line_raw) const {
|
|
FastLine *fast_line = new FastLine;
|
|
fast_line->CopyFrom(fast_line_raw);
|
|
|
|
ASSERT_TRUE(basic_line->address == fast_line->address);
|
|
ASSERT_TRUE(basic_line->size == fast_line->size);
|
|
ASSERT_TRUE(basic_line->source_file_id == fast_line->source_file_id);
|
|
ASSERT_TRUE(basic_line->line == fast_line->line);
|
|
|
|
delete fast_line;
|
|
return true;
|
|
}
|
|
|
|
bool ModuleComparer::ComparePubSymbol(const BasicPubSymbol* basic_ps,
|
|
const FastPubSymbol* fastps_raw) const {
|
|
FastPubSymbol *fast_ps = new FastPubSymbol;
|
|
fast_ps->CopyFrom(fastps_raw);
|
|
ASSERT_TRUE(basic_ps->name == fast_ps->name);
|
|
ASSERT_TRUE(basic_ps->address == fast_ps->address);
|
|
ASSERT_TRUE(basic_ps->parameter_size == fast_ps->parameter_size);
|
|
delete fast_ps;
|
|
return true;
|
|
}
|
|
|
|
bool ModuleComparer::CompareWFI(const WindowsFrameInfo& wfi1,
|
|
const WindowsFrameInfo& wfi2) const {
|
|
ASSERT_TRUE(wfi1.valid == wfi2.valid);
|
|
ASSERT_TRUE(wfi1.prolog_size == wfi2.prolog_size);
|
|
ASSERT_TRUE(wfi1.epilog_size == wfi2.epilog_size);
|
|
ASSERT_TRUE(wfi1.parameter_size == wfi2.parameter_size);
|
|
ASSERT_TRUE(wfi1.saved_register_size == wfi2.saved_register_size);
|
|
ASSERT_TRUE(wfi1.local_size == wfi2.local_size);
|
|
ASSERT_TRUE(wfi1.max_stack_size == wfi2.max_stack_size);
|
|
ASSERT_TRUE(wfi1.allocates_base_pointer == wfi2.allocates_base_pointer);
|
|
ASSERT_TRUE(wfi1.program_string == wfi2.program_string);
|
|
return true;
|
|
}
|
|
|
|
// Compare ContainedRangeMap
|
|
bool ModuleComparer::CompareCRM(
|
|
const ContainedRangeMap<MemAddr, linked_ptr<WFI> >* basic_crm,
|
|
const StaticContainedRangeMap<MemAddr, char>* fast_crm) const {
|
|
ASSERT_TRUE(basic_crm->base_ == fast_crm->base_);
|
|
|
|
if (!basic_crm->entry_.get() || !fast_crm->entry_ptr_) {
|
|
// empty entry:
|
|
ASSERT_TRUE(!basic_crm->entry_.get() && !fast_crm->entry_ptr_);
|
|
} else {
|
|
WFI newwfi;
|
|
newwfi.CopyFrom(fast_resolver_->CopyWFI(fast_crm->entry_ptr_));
|
|
ASSERT_TRUE(CompareWFI(*(basic_crm->entry_.get()), newwfi));
|
|
}
|
|
|
|
if ((!basic_crm->map_ || basic_crm->map_->empty())
|
|
|| fast_crm->map_.empty()) {
|
|
ASSERT_TRUE((!basic_crm->map_ || basic_crm->map_->empty())
|
|
&& fast_crm->map_.empty());
|
|
} else {
|
|
ContainedRangeMap<MemAddr, linked_ptr<WFI> >::MapConstIterator iter1;
|
|
StaticContainedRangeMap<MemAddr, char>::MapConstIterator iter2;
|
|
iter1 = basic_crm->map_->begin();
|
|
iter2 = fast_crm->map_.begin();
|
|
while (iter1 != basic_crm->map_->end()
|
|
&& iter2 != fast_crm->map_.end()) {
|
|
ASSERT_TRUE(iter1->first == iter2.GetKey());
|
|
StaticContainedRangeMap<MemAddr, char> *child =
|
|
new StaticContainedRangeMap<MemAddr, char>(
|
|
reinterpret_cast<const char*>(iter2.GetValuePtr()));
|
|
ASSERT_TRUE(CompareCRM(iter1->second, child));
|
|
delete child;
|
|
++iter1;
|
|
++iter2;
|
|
}
|
|
ASSERT_TRUE(iter1 == basic_crm->map_->end());
|
|
ASSERT_TRUE(iter2 == fast_crm->map_.end());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace google_breakpad
|
|
|