| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "courgette/disassembler.h" | 5 #include "courgette/disassembler.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
| (...skipping 17 matching lines...) Expand all Loading... |
| 29 incomplete_disassembly_(false) { | 29 incomplete_disassembly_(false) { |
| 30 } | 30 } |
| 31 | 31 |
| 32 virtual bool Disassemble(AssemblyProgram* target); | 32 virtual bool Disassemble(AssemblyProgram* target); |
| 33 | 33 |
| 34 virtual void Destroy() { delete this; } | 34 virtual void Destroy() { delete this; } |
| 35 | 35 |
| 36 protected: | 36 protected: |
| 37 PEInfo& pe_info() { return *pe_info_; } | 37 PEInfo& pe_info() { return *pe_info_; } |
| 38 | 38 |
| 39 void ParseFile(AssemblyProgram* target); | 39 CheckBool ParseFile(AssemblyProgram* target) WARN_UNUSED_RESULT; |
| 40 bool ParseAbs32Relocs(); | 40 bool ParseAbs32Relocs(); |
| 41 void ParseRel32RelocsFromSections(); | 41 void ParseRel32RelocsFromSections(); |
| 42 void ParseRel32RelocsFromSection(const Section* section); | 42 void ParseRel32RelocsFromSection(const Section* section); |
| 43 | 43 |
| 44 void ParseNonSectionFileRegion(uint32 start_file_offset, | 44 CheckBool ParseNonSectionFileRegion(uint32 start_file_offset, |
| 45 uint32 end_file_offset, | 45 uint32 end_file_offset, AssemblyProgram* program) WARN_UNUSED_RESULT; |
| 46 AssemblyProgram* program); | 46 CheckBool ParseFileRegion(const Section* section, |
| 47 void ParseFileRegion(const Section* section, | 47 uint32 start_file_offset, uint32 end_file_offset, |
| 48 uint32 start_file_offset, uint32 end_file_offset, | 48 AssemblyProgram* program) WARN_UNUSED_RESULT; |
| 49 AssemblyProgram* program); | |
| 50 | 49 |
| 51 #if COURGETTE_HISTOGRAM_TARGETS | 50 #if COURGETTE_HISTOGRAM_TARGETS |
| 52 void HistogramTargets(const char* kind, const std::map<RVA, int>& map); | 51 void HistogramTargets(const char* kind, const std::map<RVA, int>& map); |
| 53 #endif | 52 #endif |
| 54 | 53 |
| 55 PEInfo* pe_info_; | 54 PEInfo* pe_info_; |
| 56 bool incomplete_disassembly_; // 'true' if can leave out 'uninteresting' bits | 55 bool incomplete_disassembly_; // 'true' if can leave out 'uninteresting' bits |
| 57 | 56 |
| 58 std::vector<RVA> abs32_locations_; | 57 std::vector<RVA> abs32_locations_; |
| 59 std::vector<RVA> rel32_locations_; | 58 std::vector<RVA> rel32_locations_; |
| 60 | 59 |
| 61 #if COURGETTE_HISTOGRAM_TARGETS | 60 #if COURGETTE_HISTOGRAM_TARGETS |
| 62 std::map<RVA, int> abs32_target_rvas_; | 61 std::map<RVA, int> abs32_target_rvas_; |
| 63 std::map<RVA, int> rel32_target_rvas_; | 62 std::map<RVA, int> rel32_target_rvas_; |
| 64 #endif | 63 #endif |
| 65 }; | 64 }; |
| 66 | 65 |
| 67 bool DisassemblerWin32X86::Disassemble(AssemblyProgram* target) { | 66 bool DisassemblerWin32X86::Disassemble(AssemblyProgram* target) { |
| 68 if (!pe_info().ok()) | 67 if (!pe_info().ok()) |
| 69 return false; | 68 return false; |
| 70 | 69 |
| 71 target->set_image_base(pe_info().image_base()); | 70 target->set_image_base(pe_info().image_base()); |
| 72 | 71 |
| 73 if (!ParseAbs32Relocs()) | 72 if (!ParseAbs32Relocs()) |
| 74 return false; | 73 return false; |
| 75 | 74 |
| 76 ParseRel32RelocsFromSections(); | 75 ParseRel32RelocsFromSections(); |
| 77 | 76 |
| 78 ParseFile(target); | 77 if (!ParseFile(target)) |
| 78 return false; |
| 79 | 79 |
| 80 target->DefaultAssignIndexes(); | 80 target->DefaultAssignIndexes(); |
| 81 |
| 81 return true; | 82 return true; |
| 82 } | 83 } |
| 83 | 84 |
| 84 static uint32 Read32LittleEndian(const void* address) { | 85 static uint32 Read32LittleEndian(const void* address) { |
| 85 return *reinterpret_cast<const uint32*>(address); | 86 return *reinterpret_cast<const uint32*>(address); |
| 86 } | 87 } |
| 87 | 88 |
| 88 bool DisassemblerWin32X86::ParseAbs32Relocs() { | 89 bool DisassemblerWin32X86::ParseAbs32Relocs() { |
| 89 abs32_locations_.clear(); | 90 abs32_locations_.clear(); |
| 90 if (!pe_info().ParseRelocs(&abs32_locations_)) | 91 if (!pe_info().ParseRelocs(&abs32_locations_)) |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 ++rel32_target_rvas_[target_rva]; | 222 ++rel32_target_rvas_[target_rva]; |
| 222 #endif | 223 #endif |
| 223 p += 4; | 224 p += 4; |
| 224 continue; | 225 continue; |
| 225 } | 226 } |
| 226 } | 227 } |
| 227 p += 1; | 228 p += 1; |
| 228 } | 229 } |
| 229 } | 230 } |
| 230 | 231 |
| 231 void DisassemblerWin32X86::ParseFile(AssemblyProgram* program) { | 232 CheckBool DisassemblerWin32X86::ParseFile(AssemblyProgram* program) { |
| 233 bool ok = true; |
| 232 // Walk all the bytes in the file, whether or not in a section. | 234 // Walk all the bytes in the file, whether or not in a section. |
| 233 uint32 file_offset = 0; | 235 uint32 file_offset = 0; |
| 234 while (file_offset < pe_info().length()) { | 236 while (ok && file_offset < pe_info().length()) { |
| 235 const Section* section = pe_info().FindNextSection(file_offset); | 237 const Section* section = pe_info().FindNextSection(file_offset); |
| 236 if (section == NULL) { | 238 if (section == NULL) { |
| 237 // No more sections. There should not be extra stuff following last | 239 // No more sections. There should not be extra stuff following last |
| 238 // section. | 240 // section. |
| 239 // ParseNonSectionFileRegion(file_offset, pe_info().length(), program); | 241 // ParseNonSectionFileRegion(file_offset, pe_info().length(), program); |
| 240 break; | 242 break; |
| 241 } | 243 } |
| 242 if (file_offset < section->file_offset_of_raw_data) { | 244 if (file_offset < section->file_offset_of_raw_data) { |
| 243 uint32 section_start_offset = section->file_offset_of_raw_data; | 245 uint32 section_start_offset = section->file_offset_of_raw_data; |
| 244 ParseNonSectionFileRegion(file_offset, section_start_offset, program); | 246 ok = ParseNonSectionFileRegion(file_offset, section_start_offset, |
| 247 program); |
| 245 file_offset = section_start_offset; | 248 file_offset = section_start_offset; |
| 246 } | 249 } |
| 247 uint32 end = file_offset + section->size_of_raw_data; | 250 if (ok) { |
| 248 ParseFileRegion(section, file_offset, end, program); | 251 uint32 end = file_offset + section->size_of_raw_data; |
| 249 file_offset = end; | 252 ok = ParseFileRegion(section, file_offset, end, program); |
| 253 file_offset = end; |
| 254 } |
| 250 } | 255 } |
| 251 | 256 |
| 252 #if COURGETTE_HISTOGRAM_TARGETS | 257 #if COURGETTE_HISTOGRAM_TARGETS |
| 253 HistogramTargets("abs32 relocs", abs32_target_rvas_); | 258 HistogramTargets("abs32 relocs", abs32_target_rvas_); |
| 254 HistogramTargets("rel32 relocs", rel32_target_rvas_); | 259 HistogramTargets("rel32 relocs", rel32_target_rvas_); |
| 255 #endif | 260 #endif |
| 261 |
| 262 return ok; |
| 256 } | 263 } |
| 257 | 264 |
| 258 void DisassemblerWin32X86::ParseNonSectionFileRegion( | 265 CheckBool DisassemblerWin32X86::ParseNonSectionFileRegion( |
| 259 uint32 start_file_offset, | 266 uint32 start_file_offset, |
| 260 uint32 end_file_offset, | 267 uint32 end_file_offset, |
| 261 AssemblyProgram* program) { | 268 AssemblyProgram* program) { |
| 262 if (incomplete_disassembly_) | 269 if (incomplete_disassembly_) |
| 263 return; | 270 return true; |
| 264 | 271 |
| 265 const uint8* start = pe_info().FileOffsetToPointer(start_file_offset); | 272 const uint8* start = pe_info().FileOffsetToPointer(start_file_offset); |
| 266 const uint8* end = pe_info().FileOffsetToPointer(end_file_offset); | 273 const uint8* end = pe_info().FileOffsetToPointer(end_file_offset); |
| 267 | 274 |
| 268 const uint8* p = start; | 275 const uint8* p = start; |
| 269 | 276 |
| 270 while (p < end) { | 277 bool ok = true; |
| 271 program->EmitByteInstruction(*p); | 278 while (p < end && ok) { |
| 279 ok = program->EmitByteInstruction(*p); |
| 272 ++p; | 280 ++p; |
| 273 } | 281 } |
| 282 |
| 283 return ok; |
| 274 } | 284 } |
| 275 | 285 |
| 276 void DisassemblerWin32X86::ParseFileRegion( | 286 CheckBool DisassemblerWin32X86::ParseFileRegion( |
| 277 const Section* section, | 287 const Section* section, |
| 278 uint32 start_file_offset, uint32 end_file_offset, | 288 uint32 start_file_offset, uint32 end_file_offset, |
| 279 AssemblyProgram* program) { | 289 AssemblyProgram* program) { |
| 280 RVA relocs_start_rva = pe_info().base_relocation_table().address_; | 290 RVA relocs_start_rva = pe_info().base_relocation_table().address_; |
| 281 | 291 |
| 282 const uint8* start_pointer = pe_info().FileOffsetToPointer(start_file_offset); | 292 const uint8* start_pointer = pe_info().FileOffsetToPointer(start_file_offset); |
| 283 const uint8* end_pointer = pe_info().FileOffsetToPointer(end_file_offset); | 293 const uint8* end_pointer = pe_info().FileOffsetToPointer(end_file_offset); |
| 284 | 294 |
| 285 RVA start_rva = pe_info().FileOffsetToRVA(start_file_offset); | 295 RVA start_rva = pe_info().FileOffsetToRVA(start_file_offset); |
| 286 RVA end_rva = start_rva + section->virtual_size; | 296 RVA end_rva = start_rva + section->virtual_size; |
| 287 | 297 |
| 288 // Quick way to convert from Pointer to RVA within a single Section is to | 298 // Quick way to convert from Pointer to RVA within a single Section is to |
| 289 // subtract 'pointer_to_rva'. | 299 // subtract 'pointer_to_rva'. |
| 290 const uint8* const adjust_pointer_to_rva = start_pointer - start_rva; | 300 const uint8* const adjust_pointer_to_rva = start_pointer - start_rva; |
| 291 | 301 |
| 292 std::vector<RVA>::iterator rel32_pos = rel32_locations_.begin(); | 302 std::vector<RVA>::iterator rel32_pos = rel32_locations_.begin(); |
| 293 std::vector<RVA>::iterator abs32_pos = abs32_locations_.begin(); | 303 std::vector<RVA>::iterator abs32_pos = abs32_locations_.begin(); |
| 294 | 304 |
| 295 program->EmitOriginInstruction(start_rva); | 305 bool ok = program->EmitOriginInstruction(start_rva); |
| 296 | 306 |
| 297 const uint8* p = start_pointer; | 307 const uint8* p = start_pointer; |
| 298 | 308 |
| 299 while (p < end_pointer) { | 309 while (ok && p < end_pointer) { |
| 300 RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva); | 310 RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva); |
| 301 | 311 |
| 302 // The base relocation table is usually in the .relocs section, but it could | 312 // The base relocation table is usually in the .relocs section, but it could |
| 303 // actually be anywhere. Make sure we skip it because we will regenerate it | 313 // actually be anywhere. Make sure we skip it because we will regenerate it |
| 304 // during assembly. | 314 // during assembly. |
| 305 if (current_rva == relocs_start_rva) { | 315 if (current_rva == relocs_start_rva) { |
| 306 program->EmitMakeRelocsInstruction(); | 316 ok = program->EmitMakeRelocsInstruction(); |
| 317 if (!ok) |
| 318 break; |
| 307 uint32 relocs_size = pe_info().base_relocation_table().size_; | 319 uint32 relocs_size = pe_info().base_relocation_table().size_; |
| 308 if (relocs_size) { | 320 if (relocs_size) { |
| 309 p += relocs_size; | 321 p += relocs_size; |
| 310 continue; | 322 continue; |
| 311 } | 323 } |
| 312 } | 324 } |
| 313 | 325 |
| 314 while (abs32_pos != abs32_locations_.end() && *abs32_pos < current_rva) | 326 while (abs32_pos != abs32_locations_.end() && *abs32_pos < current_rva) |
| 315 ++abs32_pos; | 327 ++abs32_pos; |
| 316 | 328 |
| 317 if (abs32_pos != abs32_locations_.end() && *abs32_pos == current_rva) { | 329 if (abs32_pos != abs32_locations_.end() && *abs32_pos == current_rva) { |
| 318 uint32 target_address = Read32LittleEndian(p); | 330 uint32 target_address = Read32LittleEndian(p); |
| 319 RVA target_rva = target_address - pe_info().image_base(); | 331 RVA target_rva = target_address - pe_info().image_base(); |
| 320 // TODO(sra): target could be Label+offset. It is not clear how to guess | 332 // TODO(sra): target could be Label+offset. It is not clear how to guess |
| 321 // which it might be. We assume offset==0. | 333 // which it might be. We assume offset==0. |
| 322 program->EmitAbs32(program->FindOrMakeAbs32Label(target_rva)); | 334 ok = program->EmitAbs32(program->FindOrMakeAbs32Label(target_rva)); |
| 335 if (!ok) |
| 336 break; |
| 323 p += 4; | 337 p += 4; |
| 324 continue; | 338 continue; |
| 325 } | 339 } |
| 326 | 340 |
| 327 while (rel32_pos != rel32_locations_.end() && *rel32_pos < current_rva) | 341 while (rel32_pos != rel32_locations_.end() && *rel32_pos < current_rva) |
| 328 ++rel32_pos; | 342 ++rel32_pos; |
| 329 | 343 |
| 330 if (rel32_pos != rel32_locations_.end() && *rel32_pos == current_rva) { | 344 if (rel32_pos != rel32_locations_.end() && *rel32_pos == current_rva) { |
| 331 RVA target_rva = current_rva + 4 + Read32LittleEndian(p); | 345 RVA target_rva = current_rva + 4 + Read32LittleEndian(p); |
| 332 program->EmitRel32(program->FindOrMakeRel32Label(target_rva)); | 346 ok = program->EmitRel32(program->FindOrMakeRel32Label(target_rva)); |
| 333 p += 4; | 347 p += 4; |
| 334 continue; | 348 continue; |
| 335 } | 349 } |
| 336 | 350 |
| 337 if (incomplete_disassembly_) { | 351 if (incomplete_disassembly_) { |
| 338 if ((abs32_pos == abs32_locations_.end() || end_rva <= *abs32_pos) && | 352 if ((abs32_pos == abs32_locations_.end() || end_rva <= *abs32_pos) && |
| 339 (rel32_pos == rel32_locations_.end() || end_rva <= *rel32_pos) && | 353 (rel32_pos == rel32_locations_.end() || end_rva <= *rel32_pos) && |
| 340 (end_rva <= relocs_start_rva || current_rva >= relocs_start_rva)) { | 354 (end_rva <= relocs_start_rva || current_rva >= relocs_start_rva)) { |
| 341 // No more relocs in this section, don't bother encoding bytes. | 355 // No more relocs in this section, don't bother encoding bytes. |
| 342 break; | 356 break; |
| 343 } | 357 } |
| 344 } | 358 } |
| 345 | 359 |
| 346 program->EmitByteInstruction(*p); | 360 ok = program->EmitByteInstruction(*p); |
| 347 p += 1; | 361 p += 1; |
| 348 } | 362 } |
| 363 |
| 364 return ok; |
| 349 } | 365 } |
| 350 | 366 |
| 351 #if COURGETTE_HISTOGRAM_TARGETS | 367 #if COURGETTE_HISTOGRAM_TARGETS |
| 352 // Histogram is printed to std::cout. It is purely for debugging the algorithm | 368 // Histogram is printed to std::cout. It is purely for debugging the algorithm |
| 353 // and is only enabled manually in 'exploration' builds. I don't want to add | 369 // and is only enabled manually in 'exploration' builds. I don't want to add |
| 354 // command-line configuration for this feature because this code has to be | 370 // command-line configuration for this feature because this code has to be |
| 355 // small, which means compiled-out. | 371 // small, which means compiled-out. |
| 356 void DisassemblerWin32X86::HistogramTargets(const char* kind, | 372 void DisassemblerWin32X86::HistogramTargets(const char* kind, |
| 357 const std::map<RVA, int>& map) { | 373 const std::map<RVA, int>& map) { |
| 358 int total = 0; | 374 int total = 0; |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 delete pe_info; | 442 delete pe_info; |
| 427 *output = program; | 443 *output = program; |
| 428 return C_OK; | 444 return C_OK; |
| 429 } | 445 } |
| 430 | 446 |
| 431 void DeleteAssemblyProgram(AssemblyProgram* program) { | 447 void DeleteAssemblyProgram(AssemblyProgram* program) { |
| 432 delete program; | 448 delete program; |
| 433 } | 449 } |
| 434 | 450 |
| 435 } // namespace courgette | 451 } // namespace courgette |
| OLD | NEW |