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