/ src / processor / module_comparer.cc
module_comparer.cc
  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: lambxsy@google.com (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  
 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
 90  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  
194  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  
223  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  
237  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  
248  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
264  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