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 (at) 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 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 87 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 191 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 220 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 234 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 245 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 261 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