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 
53 namespace google_breakpad {
54 
Compare(const string & symbol_data)55 bool 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
CompareModule(const BasicModule * basic_module,const FastModule * fast_module) const87 bool 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 
CompareFunction(const BasicFunc * basic_func,const FastFunc * fast_func_raw) const191 bool 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 
CompareLine(const BasicLine * basic_line,const FastLine * fast_line_raw) const220 bool 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 
ComparePubSymbol(const BasicPubSymbol * basic_ps,const FastPubSymbol * fastps_raw) const234 bool 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 
CompareWFI(const WindowsFrameInfo & wfi1,const WindowsFrameInfo & wfi2) const245 bool 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
CompareCRM(const ContainedRangeMap<MemAddr,linked_ptr<WFI>> * basic_crm,const StaticContainedRangeMap<MemAddr,char> * fast_crm) const261 bool 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