1// Copyright (c) 2010, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29//
30// module_comparer.cc: ModuleComparer implementation.
31// See module_comparer.h for documentation.
32//
33// Author: lambxsy@google.com (Siyang Xie)
34
35#include "processor/module_comparer.h"
36
37#include <map>
38#include <string>
39
40#include "common/scoped_ptr.h"
41#include "processor/basic_code_module.h"
42#include "processor/logging.h"
43
44#define ASSERT_TRUE(condition) \
45 if (!(condition)) { \
46 BPLOG(ERROR) << "FAIL: " << #condition << " @ " \
47 << __FILE__ << ":" << __LINE__; \
48 return false; \
49 }
50
51#define ASSERT_FALSE(condition) ASSERT_TRUE(!(condition))
52
53namespace google_breakpad {
54
55bool ModuleComparer::Compare(const string& symbol_data) {
56 scoped_ptr<BasicModule> basic_module(new BasicModule("test_module"));
57 scoped_ptr<FastModule> fast_module(new FastModule("test_module"));
58
59 // Load symbol data into basic_module
60 scoped_array<char> buffer(new char[symbol_data.size() + 1]);
61 memcpy(buffer.get(), symbol_data.c_str(), symbol_data.size());
62 buffer.get()[symbol_data.size()] = '\0';
63 ASSERT_TRUE(basic_module->LoadMapFromMemory(buffer.get(),
64 symbol_data.size() + 1));
65 buffer.reset();
66
67 // Serialize BasicSourceLineResolver::Module.
68 unsigned int serialized_size = 0;
69 scoped_array<char> serialized_data(
70 serializer_.Serialize(*(basic_module.get()), &serialized_size));
71 ASSERT_TRUE(serialized_data.get());
72 BPLOG(INFO) << "Serialized size = " << serialized_size << " Bytes";
73
74 // Load FastSourceLineResolver::Module using serialized data.
75 ASSERT_TRUE(fast_module->LoadMapFromMemory(serialized_data.get(),
76 serialized_size));
77 ASSERT_TRUE(fast_module->IsCorrupt() == basic_module->IsCorrupt());
78
79 // Compare FastSourceLineResolver::Module with
80 // BasicSourceLineResolver::Module.
81 ASSERT_TRUE(CompareModule(basic_module.get(), fast_module.get()));
82
83 return true;
84}
85
86// Traversal the content of module and do comparison
87bool ModuleComparer::CompareModule(const BasicModule *basic_module,
88 const FastModule *fast_module) const {
89 // Compare name_.
90 ASSERT_TRUE(basic_module->name_ == fast_module->name_);
91
92 // Compare files_:
93 {
94 BasicModule::FileMap::const_iterator iter1 = basic_module->files_.begin();
95 FastModule::FileMap::iterator iter2 = fast_module->files_.begin();
96 while (iter1 != basic_module->files_.end()
97 && iter2 != fast_module->files_.end()) {
98 ASSERT_TRUE(iter1->first == iter2.GetKey());
99 string tmp(iter2.GetValuePtr());
100 ASSERT_TRUE(iter1->second == tmp);
101 ++iter1;
102 ++iter2;
103 }
104 ASSERT_TRUE(iter1 == basic_module->files_.end());
105 ASSERT_TRUE(iter2 == fast_module->files_.end());
106 }
107
108 // Compare functions_:
109 {
110 RangeMap<MemAddr, linked_ptr<BasicFunc> >::MapConstIterator iter1;
111 StaticRangeMap<MemAddr, FastFunc>::MapConstIterator iter2;
112 iter1 = basic_module->functions_.map_.begin();
113 iter2 = fast_module->functions_.map_.begin();
114 while (iter1 != basic_module->functions_.map_.end()
115 && iter2 != fast_module->functions_.map_.end()) {
116 ASSERT_TRUE(iter1->first == iter2.GetKey());
117 ASSERT_TRUE(iter1->second.base() == iter2.GetValuePtr()->base());
118 ASSERT_TRUE(CompareFunction(
119 iter1->second.entry().get(), iter2.GetValuePtr()->entryptr()));
120 ++iter1;
121 ++iter2;
122 }
123 ASSERT_TRUE(iter1 == basic_module->functions_.map_.end());
124 ASSERT_TRUE(iter2 == fast_module->functions_.map_.end());
125 }
126
127 // Compare public_symbols_:
128 {
129 AddressMap<MemAddr, linked_ptr<BasicPubSymbol> >::MapConstIterator iter1;
130 StaticAddressMap<MemAddr, FastPubSymbol>::MapConstIterator iter2;
131 iter1 = basic_module->public_symbols_.map_.begin();
132 iter2 = fast_module->public_symbols_.map_.begin();
133 while (iter1 != basic_module->public_symbols_.map_.end()
134 && iter2 != fast_module->public_symbols_.map_.end()) {
135 ASSERT_TRUE(iter1->first == iter2.GetKey());
136 ASSERT_TRUE(ComparePubSymbol(
137 iter1->second.get(), iter2.GetValuePtr()));
138 ++iter1;
139 ++iter2;
140 }
141 ASSERT_TRUE(iter1 == basic_module->public_symbols_.map_.end());
142 ASSERT_TRUE(iter2 == fast_module->public_symbols_.map_.end());
143 }
144
145 // Compare windows_frame_info_[]:
146 for (int i = 0; i < WindowsFrameInfo::STACK_INFO_LAST; ++i) {
147 ASSERT_TRUE(CompareCRM(&(basic_module->windows_frame_info_[i]),
148 &(fast_module->windows_frame_info_[i])));
149 }
150
151 // Compare cfi_initial_rules_:
152 {
153 RangeMap<MemAddr, string>::MapConstIterator iter1;
154 StaticRangeMap<MemAddr, char>::MapConstIterator iter2;
155 iter1 = basic_module->cfi_initial_rules_.map_.begin();
156 iter2 = fast_module->cfi_initial_rules_.map_.begin();
157 while (iter1 != basic_module->cfi_initial_rules_.map_.end()
158 && iter2 != fast_module->cfi_initial_rules_.map_.end()) {
159 ASSERT_TRUE(iter1->first == iter2.GetKey());
160 ASSERT_TRUE(iter1->second.base() == iter2.GetValuePtr()->base());
161 string tmp(iter2.GetValuePtr()->entryptr());
162 ASSERT_TRUE(iter1->second.entry() == tmp);
163 ++iter1;
164 ++iter2;
165 }
166 ASSERT_TRUE(iter1 == basic_module->cfi_initial_rules_.map_.end());
167 ASSERT_TRUE(iter2 == fast_module->cfi_initial_rules_.map_.end());
168 }
169
170 // Compare cfi_delta_rules_:
171 {
172 map<MemAddr, string>::const_iterator iter1;
173 StaticMap<MemAddr, char>::iterator iter2;
174 iter1 = basic_module->cfi_delta_rules_.begin();
175 iter2 = fast_module->cfi_delta_rules_.begin();
176 while (iter1 != basic_module->cfi_delta_rules_.end()
177 && iter2 != fast_module->cfi_delta_rules_.end()) {
178 ASSERT_TRUE(iter1->first == iter2.GetKey());
179 string tmp(iter2.GetValuePtr());
180 ASSERT_TRUE(iter1->second == tmp);
181 ++iter1;
182 ++iter2;
183 }
184 ASSERT_TRUE(iter1 == basic_module->cfi_delta_rules_.end());
185 ASSERT_TRUE(iter2 == fast_module->cfi_delta_rules_.end());
186 }
187
188 return true;
189}
190
191bool ModuleComparer::CompareFunction(const BasicFunc *basic_func,
192 const FastFunc *fast_func_raw) const {
193 FastFunc* fast_func = new FastFunc();
194 fast_func->CopyFrom(fast_func_raw);
195 ASSERT_TRUE(basic_func->name == fast_func->name);
196 ASSERT_TRUE(basic_func->address == fast_func->address);
197 ASSERT_TRUE(basic_func->size == fast_func->size);
198
199 // compare range map of lines:
200 RangeMap<MemAddr, linked_ptr<BasicLine> >::MapConstIterator iter1;
201 StaticRangeMap<MemAddr, FastLine>::MapConstIterator iter2;
202 iter1 = basic_func->lines.map_.begin();
203 iter2 = fast_func->lines.map_.begin();
204 while (iter1 != basic_func->lines.map_.end()
205 && iter2 != fast_func->lines.map_.end()) {
206 ASSERT_TRUE(iter1->first == iter2.GetKey());
207 ASSERT_TRUE(iter1->second.base() == iter2.GetValuePtr()->base());
208 ASSERT_TRUE(CompareLine(iter1->second.entry().get(),
209 iter2.GetValuePtr()->entryptr()));
210 ++iter1;
211 ++iter2;
212 }
213 ASSERT_TRUE(iter1 == basic_func->lines.map_.end());
214 ASSERT_TRUE(iter2 == fast_func->lines.map_.end());
215
216 delete fast_func;
217 return true;
218}
219
220bool ModuleComparer::CompareLine(const BasicLine *basic_line,
221 const FastLine *fast_line_raw) const {
222 FastLine *fast_line = new FastLine;
223 fast_line->CopyFrom(fast_line_raw);
224
225 ASSERT_TRUE(basic_line->address == fast_line->address);
226 ASSERT_TRUE(basic_line->size == fast_line->size);
227 ASSERT_TRUE(basic_line->source_file_id == fast_line->source_file_id);
228 ASSERT_TRUE(basic_line->line == fast_line->line);
229
230 delete fast_line;
231 return true;
232}
233
234bool ModuleComparer::ComparePubSymbol(const BasicPubSymbol* basic_ps,
235 const FastPubSymbol* fastps_raw) const {
236 FastPubSymbol *fast_ps = new FastPubSymbol;
237 fast_ps->CopyFrom(fastps_raw);
238 ASSERT_TRUE(basic_ps->name == fast_ps->name);
239 ASSERT_TRUE(basic_ps->address == fast_ps->address);
240 ASSERT_TRUE(basic_ps->parameter_size == fast_ps->parameter_size);
241 delete fast_ps;
242 return true;
243}
244
245bool ModuleComparer::CompareWFI(const WindowsFrameInfo& wfi1,
246 const WindowsFrameInfo& wfi2) const {
247 ASSERT_TRUE(wfi1.type_ == wfi2.type_);
248 ASSERT_TRUE(wfi1.valid == wfi2.valid);
249 ASSERT_TRUE(wfi1.prolog_size == wfi2.prolog_size);
250 ASSERT_TRUE(wfi1.epilog_size == wfi2.epilog_size);
251 ASSERT_TRUE(wfi1.parameter_size == wfi2.parameter_size);
252 ASSERT_TRUE(wfi1.saved_register_size == wfi2.saved_register_size);
253 ASSERT_TRUE(wfi1.local_size == wfi2.local_size);
254 ASSERT_TRUE(wfi1.max_stack_size == wfi2.max_stack_size);
255 ASSERT_TRUE(wfi1.allocates_base_pointer == wfi2.allocates_base_pointer);
256 ASSERT_TRUE(wfi1.program_string == wfi2.program_string);
257 return true;
258}
259
260// Compare ContainedRangeMap
261bool ModuleComparer::CompareCRM(
262 const ContainedRangeMap<MemAddr, linked_ptr<WFI> >* basic_crm,
263 const StaticContainedRangeMap<MemAddr, char>* fast_crm) const {
264 ASSERT_TRUE(basic_crm->base_ == fast_crm->base_);
265
266 if (!basic_crm->entry_.get() || !fast_crm->entry_ptr_) {
267 // empty entry:
268 ASSERT_TRUE(!basic_crm->entry_.get() && !fast_crm->entry_ptr_);
269 } else {
270 WFI newwfi;
271 newwfi.CopyFrom(fast_resolver_->CopyWFI(fast_crm->entry_ptr_));
272 ASSERT_TRUE(CompareWFI(*(basic_crm->entry_.get()), newwfi));
273 }
274
275 if ((!basic_crm->map_ || basic_crm->map_->empty())
276 || fast_crm->map_.empty()) {
277 ASSERT_TRUE((!basic_crm->map_ || basic_crm->map_->empty())
278 && fast_crm->map_.empty());
279 } else {
280 ContainedRangeMap<MemAddr, linked_ptr<WFI> >::MapConstIterator iter1;
281 StaticContainedRangeMap<MemAddr, char>::MapConstIterator iter2;
282 iter1 = basic_crm->map_->begin();
283 iter2 = fast_crm->map_.begin();
284 while (iter1 != basic_crm->map_->end()
285 && iter2 != fast_crm->map_.end()) {
286 ASSERT_TRUE(iter1->first == iter2.GetKey());
287 StaticContainedRangeMap<MemAddr, char>* child =
288 new StaticContainedRangeMap<MemAddr, char>(
289 reinterpret_cast<const char*>(iter2.GetValuePtr()));
290 ASSERT_TRUE(CompareCRM(iter1->second, child));
291 delete child;
292 ++iter1;
293 ++iter2;
294 }
295 ASSERT_TRUE(iter1 == basic_crm->map_->end());
296 ASSERT_TRUE(iter2 == fast_crm->map_.end());
297 }
298
299 return true;
300}
301
302} // namespace google_breakpad
303