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