| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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_win32_x64.h" | 5 #include "courgette/disassembler_win32_x64.h" |
| 6 | 6 |
| 7 #include <stddef.h> |
| 8 #include <stdint.h> |
| 9 |
| 7 #include <algorithm> | 10 #include <algorithm> |
| 8 #include <string> | 11 #include <string> |
| 9 #include <vector> | 12 #include <vector> |
| 10 | 13 |
| 11 #include "base/basictypes.h" | |
| 12 #include "base/logging.h" | 14 #include "base/logging.h" |
| 13 #include "base/numerics/safe_conversions.h" | 15 #include "base/numerics/safe_conversions.h" |
| 14 | 16 |
| 15 #include "courgette/assembly_program.h" | 17 #include "courgette/assembly_program.h" |
| 16 #include "courgette/courgette.h" | 18 #include "courgette/courgette.h" |
| 17 #include "courgette/encoded_program.h" | 19 #include "courgette/encoded_program.h" |
| 18 | 20 |
| 19 namespace courgette { | 21 namespace courgette { |
| 20 | 22 |
| 21 DisassemblerWin32X64::DisassemblerWin32X64(const void* start, size_t length) | 23 DisassemblerWin32X64::DisassemblerWin32X64(const void* start, size_t length) |
| (...skipping 26 matching lines...) Expand all Loading... |
| 48 // | 50 // |
| 49 bool DisassemblerWin32X64::ParseHeader() { | 51 bool DisassemblerWin32X64::ParseHeader() { |
| 50 if (length() < kOffsetOfFileAddressOfNewExeHeader + 4 /*size*/) | 52 if (length() < kOffsetOfFileAddressOfNewExeHeader + 4 /*size*/) |
| 51 return Bad("Too small"); | 53 return Bad("Too small"); |
| 52 | 54 |
| 53 // Have 'MZ' magic for a DOS header? | 55 // Have 'MZ' magic for a DOS header? |
| 54 if (start()[0] != 'M' || start()[1] != 'Z') | 56 if (start()[0] != 'M' || start()[1] != 'Z') |
| 55 return Bad("Not MZ"); | 57 return Bad("Not MZ"); |
| 56 | 58 |
| 57 // offset from DOS header to PE header is stored in DOS header. | 59 // offset from DOS header to PE header is stored in DOS header. |
| 58 uint32 offset = ReadU32(start(), | 60 uint32_t offset = ReadU32(start(), kOffsetOfFileAddressOfNewExeHeader); |
| 59 kOffsetOfFileAddressOfNewExeHeader); | |
| 60 | 61 |
| 61 if (offset >= length()) | 62 if (offset >= length()) |
| 62 return Bad("Bad offset to PE header"); | 63 return Bad("Bad offset to PE header"); |
| 63 | 64 |
| 64 const uint8* const pe_header = OffsetToPointer(offset); | 65 const uint8_t* const pe_header = OffsetToPointer(offset); |
| 65 const size_t kMinPEHeaderSize = 4 /*signature*/ + kSizeOfCoffHeader; | 66 const size_t kMinPEHeaderSize = 4 /*signature*/ + kSizeOfCoffHeader; |
| 66 if (pe_header <= start() || | 67 if (pe_header <= start() || |
| 67 pe_header >= end() - kMinPEHeaderSize) | 68 pe_header >= end() - kMinPEHeaderSize) |
| 68 return Bad("Bad offset to PE header"); | 69 return Bad("Bad offset to PE header"); |
| 69 | 70 |
| 70 if (offset % 8 != 0) | 71 if (offset % 8 != 0) |
| 71 return Bad("Misaligned PE header"); | 72 return Bad("Misaligned PE header"); |
| 72 | 73 |
| 73 // The 'PE' header is an IMAGE_NT_HEADERS structure as defined in WINNT.H. | 74 // The 'PE' header is an IMAGE_NT_HEADERS structure as defined in WINNT.H. |
| 74 // See http://msdn.microsoft.com/en-us/library/ms680336(VS.85).aspx | 75 // See http://msdn.microsoft.com/en-us/library/ms680336(VS.85).aspx |
| 75 // | 76 // |
| 76 // The first field of the IMAGE_NT_HEADERS is the signature. | 77 // The first field of the IMAGE_NT_HEADERS is the signature. |
| 77 if (!(pe_header[0] == 'P' && | 78 if (!(pe_header[0] == 'P' && |
| 78 pe_header[1] == 'E' && | 79 pe_header[1] == 'E' && |
| 79 pe_header[2] == 0 && | 80 pe_header[2] == 0 && |
| 80 pe_header[3] == 0)) | 81 pe_header[3] == 0)) |
| 81 return Bad("no PE signature"); | 82 return Bad("no PE signature"); |
| 82 | 83 |
| 83 // The second field of the IMAGE_NT_HEADERS is the COFF header. | 84 // The second field of the IMAGE_NT_HEADERS is the COFF header. |
| 84 // The COFF header is also called an IMAGE_FILE_HEADER | 85 // The COFF header is also called an IMAGE_FILE_HEADER |
| 85 // http://msdn.microsoft.com/en-us/library/ms680313(VS.85).aspx | 86 // http://msdn.microsoft.com/en-us/library/ms680313(VS.85).aspx |
| 86 const uint8* const coff_header = pe_header + 4; | 87 const uint8_t* const coff_header = pe_header + 4; |
| 87 machine_type_ = ReadU16(coff_header, 0); | 88 machine_type_ = ReadU16(coff_header, 0); |
| 88 number_of_sections_ = ReadU16(coff_header, 2); | 89 number_of_sections_ = ReadU16(coff_header, 2); |
| 89 size_of_optional_header_ = ReadU16(coff_header, 16); | 90 size_of_optional_header_ = ReadU16(coff_header, 16); |
| 90 | 91 |
| 91 // The rest of the IMAGE_NT_HEADERS is the IMAGE_OPTIONAL_HEADER(32|64) | 92 // The rest of the IMAGE_NT_HEADERS is the IMAGE_OPTIONAL_HEADER(32|64) |
| 92 const uint8* const optional_header = coff_header + kSizeOfCoffHeader; | 93 const uint8_t* const optional_header = coff_header + kSizeOfCoffHeader; |
| 93 optional_header_ = optional_header; | 94 optional_header_ = optional_header; |
| 94 | 95 |
| 95 if (optional_header + size_of_optional_header_ >= end()) | 96 if (optional_header + size_of_optional_header_ >= end()) |
| 96 return Bad("optional header past end of file"); | 97 return Bad("optional header past end of file"); |
| 97 | 98 |
| 98 // Check we can read the magic. | 99 // Check we can read the magic. |
| 99 if (size_of_optional_header_ < 2) | 100 if (size_of_optional_header_ < 2) |
| 100 return Bad("optional header no magic"); | 101 return Bad("optional header no magic"); |
| 101 | 102 |
| 102 uint16 magic = ReadU16(optional_header, 0); | 103 uint16_t magic = ReadU16(optional_header, 0); |
| 103 | 104 |
| 104 if (magic == kImageNtOptionalHdr32Magic) { | 105 if (magic == kImageNtOptionalHdr32Magic) { |
| 105 is_PE32_plus_ = false; | 106 is_PE32_plus_ = false; |
| 106 offset_of_data_directories_ = | 107 offset_of_data_directories_ = |
| 107 kOffsetOfDataDirectoryFromImageOptionalHeader32; | 108 kOffsetOfDataDirectoryFromImageOptionalHeader32; |
| 108 } else if (magic == kImageNtOptionalHdr64Magic) { | 109 } else if (magic == kImageNtOptionalHdr64Magic) { |
| 109 is_PE32_plus_ = true; | 110 is_PE32_plus_ = true; |
| 110 offset_of_data_directories_ = | 111 offset_of_data_directories_ = |
| 111 kOffsetOfDataDirectoryFromImageOptionalHeader64; | 112 kOffsetOfDataDirectoryFromImageOptionalHeader64; |
| 112 } else { | 113 } else { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 size_t detected_length = 0; | 170 size_t detected_length = 0; |
| 170 | 171 |
| 171 for (int i = 0; i < number_of_sections_; ++i) { | 172 for (int i = 0; i < number_of_sections_; ++i) { |
| 172 const Section* section = §ions_[i]; | 173 const Section* section = §ions_[i]; |
| 173 | 174 |
| 174 // TODO(sra): consider using the 'characteristics' field of the section | 175 // TODO(sra): consider using the 'characteristics' field of the section |
| 175 // header to see if the section contains instructions. | 176 // header to see if the section contains instructions. |
| 176 if (memcmp(section->name, ".text", 6) == 0) | 177 if (memcmp(section->name, ".text", 6) == 0) |
| 177 has_text_section_ = true; | 178 has_text_section_ = true; |
| 178 | 179 |
| 179 uint32 section_end = | 180 uint32_t section_end = |
| 180 section->file_offset_of_raw_data + section->size_of_raw_data; | 181 section->file_offset_of_raw_data + section->size_of_raw_data; |
| 181 if (section_end > detected_length) | 182 if (section_end > detected_length) |
| 182 detected_length = section_end; | 183 detected_length = section_end; |
| 183 } | 184 } |
| 184 | 185 |
| 185 // Pretend our in-memory copy is only as long as our detected length. | 186 // Pretend our in-memory copy is only as long as our detected length. |
| 186 ReduceLength(detected_length); | 187 ReduceLength(detected_length); |
| 187 | 188 |
| 188 if (is_32bit()) { | 189 if (is_32bit()) { |
| 189 return Bad("32 bit executables are not supported by this disassembler"); | 190 return Bad("32 bit executables are not supported by this disassembler"); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 222 | 223 |
| 223 size_t relocs_size = base_relocation_table_.size_; | 224 size_t relocs_size = base_relocation_table_.size_; |
| 224 if (relocs_size == 0) | 225 if (relocs_size == 0) |
| 225 return true; | 226 return true; |
| 226 | 227 |
| 227 // The format of the base relocation table is a sequence of variable sized | 228 // The format of the base relocation table is a sequence of variable sized |
| 228 // IMAGE_BASE_RELOCATION blocks. Search for | 229 // IMAGE_BASE_RELOCATION blocks. Search for |
| 229 // "The format of the base relocation data is somewhat quirky" | 230 // "The format of the base relocation data is somewhat quirky" |
| 230 // at http://msdn.microsoft.com/en-us/library/ms809762.aspx | 231 // at http://msdn.microsoft.com/en-us/library/ms809762.aspx |
| 231 | 232 |
| 232 const uint8* relocs_start = RVAToPointer(base_relocation_table_.address_); | 233 const uint8_t* relocs_start = RVAToPointer(base_relocation_table_.address_); |
| 233 const uint8* relocs_end = relocs_start + relocs_size; | 234 const uint8_t* relocs_end = relocs_start + relocs_size; |
| 234 | 235 |
| 235 // Make sure entire base relocation table is within the buffer. | 236 // Make sure entire base relocation table is within the buffer. |
| 236 if (relocs_start < start() || | 237 if (relocs_start < start() || |
| 237 relocs_start >= end() || | 238 relocs_start >= end() || |
| 238 relocs_end <= start() || | 239 relocs_end <= start() || |
| 239 relocs_end > end()) { | 240 relocs_end > end()) { |
| 240 return Bad(".relocs outside image"); | 241 return Bad(".relocs outside image"); |
| 241 } | 242 } |
| 242 | 243 |
| 243 const uint8* block = relocs_start; | 244 const uint8_t* block = relocs_start; |
| 244 | 245 |
| 245 // Walk the variable sized blocks. | 246 // Walk the variable sized blocks. |
| 246 while (block + 8 < relocs_end) { | 247 while (block + 8 < relocs_end) { |
| 247 RVA page_rva = ReadU32(block, 0); | 248 RVA page_rva = ReadU32(block, 0); |
| 248 uint32 size = ReadU32(block, 4); | 249 uint32_t size = ReadU32(block, 4); |
| 249 if (size < 8 || // Size includes header ... | 250 if (size < 8 || // Size includes header ... |
| 250 size % 4 != 0) // ... and is word aligned. | 251 size % 4 != 0) // ... and is word aligned. |
| 251 return Bad("unreasonable relocs block"); | 252 return Bad("unreasonable relocs block"); |
| 252 | 253 |
| 253 const uint8* end_entries = block + size; | 254 const uint8_t* end_entries = block + size; |
| 254 | 255 |
| 255 if (end_entries <= block || | 256 if (end_entries <= block || |
| 256 end_entries <= start() || | 257 end_entries <= start() || |
| 257 end_entries > end()) | 258 end_entries > end()) |
| 258 return Bad(".relocs block outside image"); | 259 return Bad(".relocs block outside image"); |
| 259 | 260 |
| 260 // Walk through the two-byte entries. | 261 // Walk through the two-byte entries. |
| 261 for (const uint8* p = block + 8; p < end_entries; p += 2) { | 262 for (const uint8_t* p = block + 8; p < end_entries; p += 2) { |
| 262 uint16 entry = ReadU16(p, 0); | 263 uint16_t entry = ReadU16(p, 0); |
| 263 int type = entry >> 12; | 264 int type = entry >> 12; |
| 264 int offset = entry & 0xFFF; | 265 int offset = entry & 0xFFF; |
| 265 | 266 |
| 266 RVA rva = page_rva + offset; | 267 RVA rva = page_rva + offset; |
| 267 // TODO(sebmarchand): Skip the relocs that live outside of the image. See | 268 // TODO(sebmarchand): Skip the relocs that live outside of the image. See |
| 268 // the version of this function in disassembler_win32_x86.cc. | 269 // the version of this function in disassembler_win32_x86.cc. |
| 269 if (type == 10) { // IMAGE_REL_BASED_DIR64 | 270 if (type == 10) { // IMAGE_REL_BASED_DIR64 |
| 270 relocs->push_back(rva); | 271 relocs->push_back(rva); |
| 271 } else if (type == 0) { // IMAGE_REL_BASED_ABSOLUTE | 272 } else if (type == 0) { // IMAGE_REL_BASED_ABSOLUTE |
| 272 // Ignore, used as padding. | 273 // Ignore, used as padding. |
| 273 } else { | 274 } else { |
| 274 // Does not occur in Windows x64 executables. | 275 // Does not occur in Windows x64 executables. |
| 275 return Bad("unknown type of reloc"); | 276 return Bad("unknown type of reloc"); |
| 276 } | 277 } |
| 277 } | 278 } |
| 278 | 279 |
| 279 block += size; | 280 block += size; |
| 280 } | 281 } |
| 281 | 282 |
| 282 std::sort(relocs->begin(), relocs->end()); | 283 std::sort(relocs->begin(), relocs->end()); |
| 283 | 284 |
| 284 return true; | 285 return true; |
| 285 } | 286 } |
| 286 | 287 |
| 287 const Section* DisassemblerWin32X64::RVAToSection(RVA rva) const { | 288 const Section* DisassemblerWin32X64::RVAToSection(RVA rva) const { |
| 288 for (int i = 0; i < number_of_sections_; i++) { | 289 for (int i = 0; i < number_of_sections_; i++) { |
| 289 const Section* section = §ions_[i]; | 290 const Section* section = §ions_[i]; |
| 290 uint32 offset = rva - section->virtual_address; | 291 uint32_t offset = rva - section->virtual_address; |
| 291 if (offset < section->virtual_size) { | 292 if (offset < section->virtual_size) { |
| 292 return section; | 293 return section; |
| 293 } | 294 } |
| 294 } | 295 } |
| 295 return NULL; | 296 return NULL; |
| 296 } | 297 } |
| 297 | 298 |
| 298 int DisassemblerWin32X64::RVAToFileOffset(RVA rva) const { | 299 int DisassemblerWin32X64::RVAToFileOffset(RVA rva) const { |
| 299 const Section* section = RVAToSection(rva); | 300 const Section* section = RVAToSection(rva); |
| 300 if (section) { | 301 if (section) { |
| 301 uint32 offset = rva - section->virtual_address; | 302 uint32_t offset = rva - section->virtual_address; |
| 302 if (offset < section->size_of_raw_data) { | 303 if (offset < section->size_of_raw_data) { |
| 303 return section->file_offset_of_raw_data + offset; | 304 return section->file_offset_of_raw_data + offset; |
| 304 } else { | 305 } else { |
| 305 return kNoOffset; // In section but not in file (e.g. uninit data). | 306 return kNoOffset; // In section but not in file (e.g. uninit data). |
| 306 } | 307 } |
| 307 } | 308 } |
| 308 | 309 |
| 309 // Small RVA values point into the file header in the loaded image. | 310 // Small RVA values point into the file header in the loaded image. |
| 310 // RVA 0 is the module load address which Windows uses as the module handle. | 311 // RVA 0 is the module load address which Windows uses as the module handle. |
| 311 // RVA 2 sometimes occurs, I'm not sure what it is, but it would map into the | 312 // RVA 2 sometimes occurs, I'm not sure what it is, but it would map into the |
| 312 // DOS header. | 313 // DOS header. |
| 313 if (rva == 0 || rva == 2) | 314 if (rva == 0 || rva == 2) |
| 314 return rva; | 315 return rva; |
| 315 | 316 |
| 316 NOTREACHED(); | 317 NOTREACHED(); |
| 317 return kNoOffset; | 318 return kNoOffset; |
| 318 } | 319 } |
| 319 | 320 |
| 320 const uint8* DisassemblerWin32X64::RVAToPointer(RVA rva) const { | 321 const uint8_t* DisassemblerWin32X64::RVAToPointer(RVA rva) const { |
| 321 int file_offset = RVAToFileOffset(rva); | 322 int file_offset = RVAToFileOffset(rva); |
| 322 if (file_offset == kNoOffset) | 323 if (file_offset == kNoOffset) |
| 323 return NULL; | 324 return NULL; |
| 324 else | 325 else |
| 325 return OffsetToPointer(file_offset); | 326 return OffsetToPointer(file_offset); |
| 326 } | 327 } |
| 327 | 328 |
| 328 std::string DisassemblerWin32X64::SectionName(const Section* section) { | 329 std::string DisassemblerWin32X64::SectionName(const Section* section) { |
| 329 if (section == NULL) | 330 if (section == NULL) |
| 330 return "<none>"; | 331 return "<none>"; |
| 331 char name[9]; | 332 char name[9]; |
| 332 memcpy(name, section->name, 8); | 333 memcpy(name, section->name, 8); |
| 333 name[8] = '\0'; // Ensure termination. | 334 name[8] = '\0'; // Ensure termination. |
| 334 return name; | 335 return name; |
| 335 } | 336 } |
| 336 | 337 |
| 337 CheckBool DisassemblerWin32X64::ParseFile(AssemblyProgram* program) { | 338 CheckBool DisassemblerWin32X64::ParseFile(AssemblyProgram* program) { |
| 338 // Walk all the bytes in the file, whether or not in a section. | 339 // Walk all the bytes in the file, whether or not in a section. |
| 339 uint32 file_offset = 0; | 340 uint32_t file_offset = 0; |
| 340 while (file_offset < length()) { | 341 while (file_offset < length()) { |
| 341 const Section* section = FindNextSection(file_offset); | 342 const Section* section = FindNextSection(file_offset); |
| 342 if (section == NULL) { | 343 if (section == NULL) { |
| 343 // No more sections. There should not be extra stuff following last | 344 // No more sections. There should not be extra stuff following last |
| 344 // section. | 345 // section. |
| 345 // ParseNonSectionFileRegion(file_offset, pe_info().length(), program); | 346 // ParseNonSectionFileRegion(file_offset, pe_info().length(), program); |
| 346 break; | 347 break; |
| 347 } | 348 } |
| 348 if (file_offset < section->file_offset_of_raw_data) { | 349 if (file_offset < section->file_offset_of_raw_data) { |
| 349 uint32 section_start_offset = section->file_offset_of_raw_data; | 350 uint32_t section_start_offset = section->file_offset_of_raw_data; |
| 350 if(!ParseNonSectionFileRegion(file_offset, section_start_offset, | 351 if(!ParseNonSectionFileRegion(file_offset, section_start_offset, |
| 351 program)) | 352 program)) |
| 352 return false; | 353 return false; |
| 353 | 354 |
| 354 file_offset = section_start_offset; | 355 file_offset = section_start_offset; |
| 355 } | 356 } |
| 356 uint32 end = file_offset + section->size_of_raw_data; | 357 uint32_t end = file_offset + section->size_of_raw_data; |
| 357 if (!ParseFileRegion(section, file_offset, end, program)) | 358 if (!ParseFileRegion(section, file_offset, end, program)) |
| 358 return false; | 359 return false; |
| 359 file_offset = end; | 360 file_offset = end; |
| 360 } | 361 } |
| 361 | 362 |
| 362 #if COURGETTE_HISTOGRAM_TARGETS | 363 #if COURGETTE_HISTOGRAM_TARGETS |
| 363 HistogramTargets("abs32 relocs", abs32_target_rvas_); | 364 HistogramTargets("abs32 relocs", abs32_target_rvas_); |
| 364 HistogramTargets("rel32 relocs", rel32_target_rvas_); | 365 HistogramTargets("rel32 relocs", rel32_target_rvas_); |
| 365 #endif | 366 #endif |
| 366 | 367 |
| 367 return true; | 368 return true; |
| 368 } | 369 } |
| 369 | 370 |
| 370 bool DisassemblerWin32X64::ParseAbs32Relocs() { | 371 bool DisassemblerWin32X64::ParseAbs32Relocs() { |
| 371 abs32_locations_.clear(); | 372 abs32_locations_.clear(); |
| 372 if (!ParseRelocs(&abs32_locations_)) | 373 if (!ParseRelocs(&abs32_locations_)) |
| 373 return false; | 374 return false; |
| 374 | 375 |
| 375 #if COURGETTE_HISTOGRAM_TARGETS | 376 #if COURGETTE_HISTOGRAM_TARGETS |
| 376 for (size_t i = 0; i < abs32_locations_.size(); ++i) { | 377 for (size_t i = 0; i < abs32_locations_.size(); ++i) { |
| 377 RVA rva = abs32_locations_[i]; | 378 RVA rva = abs32_locations_[i]; |
| 378 // The 4 bytes at the relocation are a reference to some address. | 379 // The 4 bytes at the relocation are a reference to some address. |
| 379 uint32 target_address = Read32LittleEndian(RVAToPointer(rva)); | 380 uint32_t target_address = Read32LittleEndian(RVAToPointer(rva)); |
| 380 ++abs32_target_rvas_[target_address - image_base()]; | 381 ++abs32_target_rvas_[target_address - image_base()]; |
| 381 } | 382 } |
| 382 #endif | 383 #endif |
| 383 return true; | 384 return true; |
| 384 } | 385 } |
| 385 | 386 |
| 386 void DisassemblerWin32X64::ParseRel32RelocsFromSections() { | 387 void DisassemblerWin32X64::ParseRel32RelocsFromSections() { |
| 387 uint32 file_offset = 0; | 388 uint32_t file_offset = 0; |
| 388 while (file_offset < length()) { | 389 while (file_offset < length()) { |
| 389 const Section* section = FindNextSection(file_offset); | 390 const Section* section = FindNextSection(file_offset); |
| 390 if (section == NULL) | 391 if (section == NULL) |
| 391 break; | 392 break; |
| 392 if (file_offset < section->file_offset_of_raw_data) | 393 if (file_offset < section->file_offset_of_raw_data) |
| 393 file_offset = section->file_offset_of_raw_data; | 394 file_offset = section->file_offset_of_raw_data; |
| 394 ParseRel32RelocsFromSection(section); | 395 ParseRel32RelocsFromSection(section); |
| 395 file_offset += section->size_of_raw_data; | 396 file_offset += section->size_of_raw_data; |
| 396 } | 397 } |
| 397 std::sort(rel32_locations_.begin(), rel32_locations_.end()); | 398 std::sort(rel32_locations_.begin(), rel32_locations_.end()); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 420 VLOG(1) << "common " << common; | 421 VLOG(1) << "common " << common; |
| 421 #endif | 422 #endif |
| 422 } | 423 } |
| 423 | 424 |
| 424 void DisassemblerWin32X64::ParseRel32RelocsFromSection(const Section* section) { | 425 void DisassemblerWin32X64::ParseRel32RelocsFromSection(const Section* section) { |
| 425 // TODO(sra): use characteristic. | 426 // TODO(sra): use characteristic. |
| 426 bool isCode = strcmp(section->name, ".text") == 0; | 427 bool isCode = strcmp(section->name, ".text") == 0; |
| 427 if (!isCode) | 428 if (!isCode) |
| 428 return; | 429 return; |
| 429 | 430 |
| 430 uint32 start_file_offset = section->file_offset_of_raw_data; | 431 uint32_t start_file_offset = section->file_offset_of_raw_data; |
| 431 uint32 end_file_offset = start_file_offset + section->size_of_raw_data; | 432 uint32_t end_file_offset = start_file_offset + section->size_of_raw_data; |
| 432 RVA relocs_start_rva = base_relocation_table().address_; | 433 RVA relocs_start_rva = base_relocation_table().address_; |
| 433 | 434 |
| 434 const uint8* start_pointer = OffsetToPointer(start_file_offset); | 435 const uint8_t* start_pointer = OffsetToPointer(start_file_offset); |
| 435 const uint8* end_pointer = OffsetToPointer(end_file_offset); | 436 const uint8_t* end_pointer = OffsetToPointer(end_file_offset); |
| 436 | 437 |
| 437 RVA start_rva = FileOffsetToRVA(start_file_offset); | 438 RVA start_rva = FileOffsetToRVA(start_file_offset); |
| 438 RVA end_rva = start_rva + section->virtual_size; | 439 RVA end_rva = start_rva + section->virtual_size; |
| 439 | 440 |
| 440 // Quick way to convert from Pointer to RVA within a single Section is to | 441 // Quick way to convert from Pointer to RVA within a single Section is to |
| 441 // subtract 'pointer_to_rva'. | 442 // subtract 'pointer_to_rva'. |
| 442 const uint8* const adjust_pointer_to_rva = start_pointer - start_rva; | 443 const uint8_t* const adjust_pointer_to_rva = start_pointer - start_rva; |
| 443 | 444 |
| 444 std::vector<RVA>::iterator abs32_pos = abs32_locations_.begin(); | 445 std::vector<RVA>::iterator abs32_pos = abs32_locations_.begin(); |
| 445 | 446 |
| 446 // Find the rel32 relocations. | 447 // Find the rel32 relocations. |
| 447 const uint8* p = start_pointer; | 448 const uint8_t* p = start_pointer; |
| 448 while (p < end_pointer) { | 449 while (p < end_pointer) { |
| 449 RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva); | 450 RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva); |
| 450 if (current_rva == relocs_start_rva) { | 451 if (current_rva == relocs_start_rva) { |
| 451 uint32 relocs_size = base_relocation_table().size_; | 452 uint32_t relocs_size = base_relocation_table().size_; |
| 452 if (relocs_size) { | 453 if (relocs_size) { |
| 453 p += relocs_size; | 454 p += relocs_size; |
| 454 continue; | 455 continue; |
| 455 } | 456 } |
| 456 } | 457 } |
| 457 | 458 |
| 458 //while (abs32_pos != abs32_locations_.end() && *abs32_pos < current_rva) | 459 //while (abs32_pos != abs32_locations_.end() && *abs32_pos < current_rva) |
| 459 // ++abs32_pos; | 460 // ++abs32_pos; |
| 460 | 461 |
| 461 // Heuristic discovery of rel32 locations in instruction stream: are the | 462 // Heuristic discovery of rel32 locations in instruction stream: are the |
| 462 // next few bytes the start of an instruction containing a rel32 | 463 // next few bytes the start of an instruction containing a rel32 |
| 463 // addressing mode? | 464 // addressing mode? |
| 464 const uint8* rel32 = NULL; | 465 const uint8_t* rel32 = NULL; |
| 465 bool is_rip_relative = false; | 466 bool is_rip_relative = false; |
| 466 | 467 |
| 467 if (p + 5 <= end_pointer) { | 468 if (p + 5 <= end_pointer) { |
| 468 if (*p == 0xE8 || *p == 0xE9) // jmp rel32 and call rel32 | 469 if (*p == 0xE8 || *p == 0xE9) // jmp rel32 and call rel32 |
| 469 rel32 = p + 1; | 470 rel32 = p + 1; |
| 470 } | 471 } |
| 471 if (p + 6 <= end_pointer) { | 472 if (p + 6 <= end_pointer) { |
| 472 if (*p == 0x0F && (*(p + 1) & 0xF0) == 0x80) { // Jcc long form | 473 if (*p == 0x0F && (*(p + 1) & 0xF0) == 0x80) { // Jcc long form |
| 473 if (p[1] != 0x8A && p[1] != 0x8B) // JPE/JPO unlikely | 474 if (p[1] != 0x8A && p[1] != 0x8B) // JPE/JPO unlikely |
| 474 rel32 = p + 2; | 475 rel32 = p + 2; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 521 #endif | 522 #endif |
| 522 p = rel32 + 4; | 523 p = rel32 + 4; |
| 523 continue; | 524 continue; |
| 524 } | 525 } |
| 525 } | 526 } |
| 526 p += 1; | 527 p += 1; |
| 527 } | 528 } |
| 528 } | 529 } |
| 529 | 530 |
| 530 CheckBool DisassemblerWin32X64::ParseNonSectionFileRegion( | 531 CheckBool DisassemblerWin32X64::ParseNonSectionFileRegion( |
| 531 uint32 start_file_offset, | 532 uint32_t start_file_offset, |
| 532 uint32 end_file_offset, | 533 uint32_t end_file_offset, |
| 533 AssemblyProgram* program) { | 534 AssemblyProgram* program) { |
| 534 if (incomplete_disassembly_) | 535 if (incomplete_disassembly_) |
| 535 return true; | 536 return true; |
| 536 | 537 |
| 537 if (end_file_offset > start_file_offset) { | 538 if (end_file_offset > start_file_offset) { |
| 538 if (!program->EmitBytesInstruction(OffsetToPointer(start_file_offset), | 539 if (!program->EmitBytesInstruction(OffsetToPointer(start_file_offset), |
| 539 end_file_offset - start_file_offset)) { | 540 end_file_offset - start_file_offset)) { |
| 540 return false; | 541 return false; |
| 541 } | 542 } |
| 542 } | 543 } |
| 543 | 544 |
| 544 return true; | 545 return true; |
| 545 } | 546 } |
| 546 | 547 |
| 547 CheckBool DisassemblerWin32X64::ParseFileRegion( | 548 CheckBool DisassemblerWin32X64::ParseFileRegion(const Section* section, |
| 548 const Section* section, | 549 uint32_t start_file_offset, |
| 549 uint32 start_file_offset, uint32 end_file_offset, | 550 uint32_t end_file_offset, |
| 550 AssemblyProgram* program) { | 551 AssemblyProgram* program) { |
| 551 RVA relocs_start_rva = base_relocation_table().address_; | 552 RVA relocs_start_rva = base_relocation_table().address_; |
| 552 | 553 |
| 553 const uint8* start_pointer = OffsetToPointer(start_file_offset); | 554 const uint8_t* start_pointer = OffsetToPointer(start_file_offset); |
| 554 const uint8* end_pointer = OffsetToPointer(end_file_offset); | 555 const uint8_t* end_pointer = OffsetToPointer(end_file_offset); |
| 555 | 556 |
| 556 RVA start_rva = FileOffsetToRVA(start_file_offset); | 557 RVA start_rva = FileOffsetToRVA(start_file_offset); |
| 557 RVA end_rva = start_rva + section->virtual_size; | 558 RVA end_rva = start_rva + section->virtual_size; |
| 558 | 559 |
| 559 // Quick way to convert from Pointer to RVA within a single Section is to | 560 // Quick way to convert from Pointer to RVA within a single Section is to |
| 560 // subtract 'pointer_to_rva'. | 561 // subtract 'pointer_to_rva'. |
| 561 const uint8* const adjust_pointer_to_rva = start_pointer - start_rva; | 562 const uint8_t* const adjust_pointer_to_rva = start_pointer - start_rva; |
| 562 | 563 |
| 563 std::vector<RVA>::iterator rel32_pos = rel32_locations_.begin(); | 564 std::vector<RVA>::iterator rel32_pos = rel32_locations_.begin(); |
| 564 std::vector<RVA>::iterator abs32_pos = abs32_locations_.begin(); | 565 std::vector<RVA>::iterator abs32_pos = abs32_locations_.begin(); |
| 565 | 566 |
| 566 if (!program->EmitOriginInstruction(start_rva)) | 567 if (!program->EmitOriginInstruction(start_rva)) |
| 567 return false; | 568 return false; |
| 568 | 569 |
| 569 const uint8* p = start_pointer; | 570 const uint8_t* p = start_pointer; |
| 570 | 571 |
| 571 while (p < end_pointer) { | 572 while (p < end_pointer) { |
| 572 RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva); | 573 RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva); |
| 573 | 574 |
| 574 // The base relocation table is usually in the .relocs section, but it could | 575 // The base relocation table is usually in the .relocs section, but it could |
| 575 // actually be anywhere. Make sure we skip it because we will regenerate it | 576 // actually be anywhere. Make sure we skip it because we will regenerate it |
| 576 // during assembly. | 577 // during assembly. |
| 577 if (current_rva == relocs_start_rva) { | 578 if (current_rva == relocs_start_rva) { |
| 578 if (!program->EmitPeRelocsInstruction()) | 579 if (!program->EmitPeRelocsInstruction()) |
| 579 return false; | 580 return false; |
| 580 uint32 relocs_size = base_relocation_table().size_; | 581 uint32_t relocs_size = base_relocation_table().size_; |
| 581 if (relocs_size) { | 582 if (relocs_size) { |
| 582 p += relocs_size; | 583 p += relocs_size; |
| 583 continue; | 584 continue; |
| 584 } | 585 } |
| 585 } | 586 } |
| 586 | 587 |
| 587 while (abs32_pos != abs32_locations_.end() && *abs32_pos < current_rva) | 588 while (abs32_pos != abs32_locations_.end() && *abs32_pos < current_rva) |
| 588 ++abs32_pos; | 589 ++abs32_pos; |
| 589 | 590 |
| 590 if (abs32_pos != abs32_locations_.end() && *abs32_pos == current_rva) { | 591 if (abs32_pos != abs32_locations_.end() && *abs32_pos == current_rva) { |
| 591 uint64 target_address = Read64LittleEndian(p); | 592 uint64_t target_address = Read64LittleEndian(p); |
| 592 RVA target_rva = base::checked_cast<RVA>(target_address - image_base()); | 593 RVA target_rva = base::checked_cast<RVA>(target_address - image_base()); |
| 593 // TODO(sra): target could be Label+offset. It is not clear how to guess | 594 // TODO(sra): target could be Label+offset. It is not clear how to guess |
| 594 // which it might be. We assume offset==0. | 595 // which it might be. We assume offset==0. |
| 595 if (!program->EmitAbs64(program->FindOrMakeAbs32Label(target_rva))) | 596 if (!program->EmitAbs64(program->FindOrMakeAbs32Label(target_rva))) |
| 596 return false; | 597 return false; |
| 597 p += 8; | 598 p += 8; |
| 598 continue; | 599 continue; |
| 599 } | 600 } |
| 600 | 601 |
| 601 while (rel32_pos != rel32_locations_.end() && *rel32_pos < current_rva) | 602 while (rel32_pos != rel32_locations_.end() && *rel32_pos < current_rva) |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 683 s << std::hex << rva; | 684 s << std::hex << rva; |
| 684 if (section) { | 685 if (section) { |
| 685 s << " ("; | 686 s << " ("; |
| 686 s << SectionName(section) << "+" | 687 s << SectionName(section) << "+" |
| 687 << std::hex << (rva - section->virtual_address) | 688 << std::hex << (rva - section->virtual_address) |
| 688 << ")"; | 689 << ")"; |
| 689 } | 690 } |
| 690 return s.str(); | 691 return s.str(); |
| 691 } | 692 } |
| 692 | 693 |
| 693 const Section* DisassemblerWin32X64::FindNextSection(uint32 fileOffset) const { | 694 const Section* DisassemblerWin32X64::FindNextSection( |
| 695 uint32_t fileOffset) const { |
| 694 const Section* best = 0; | 696 const Section* best = 0; |
| 695 for (int i = 0; i < number_of_sections_; i++) { | 697 for (int i = 0; i < number_of_sections_; i++) { |
| 696 const Section* section = §ions_[i]; | 698 const Section* section = §ions_[i]; |
| 697 if (section->size_of_raw_data > 0) { // i.e. has data in file. | 699 if (section->size_of_raw_data > 0) { // i.e. has data in file. |
| 698 if (fileOffset <= section->file_offset_of_raw_data) { | 700 if (fileOffset <= section->file_offset_of_raw_data) { |
| 699 if (best == 0 || | 701 if (best == 0 || |
| 700 section->file_offset_of_raw_data < best->file_offset_of_raw_data) { | 702 section->file_offset_of_raw_data < best->file_offset_of_raw_data) { |
| 701 best = section; | 703 best = section; |
| 702 } | 704 } |
| 703 } | 705 } |
| 704 } | 706 } |
| 705 } | 707 } |
| 706 return best; | 708 return best; |
| 707 } | 709 } |
| 708 | 710 |
| 709 RVA DisassemblerWin32X64::FileOffsetToRVA(uint32 file_offset) const { | 711 RVA DisassemblerWin32X64::FileOffsetToRVA(uint32_t file_offset) const { |
| 710 for (int i = 0; i < number_of_sections_; i++) { | 712 for (int i = 0; i < number_of_sections_; i++) { |
| 711 const Section* section = §ions_[i]; | 713 const Section* section = §ions_[i]; |
| 712 uint32 offset = file_offset - section->file_offset_of_raw_data; | 714 uint32_t offset = file_offset - section->file_offset_of_raw_data; |
| 713 if (offset < section->size_of_raw_data) { | 715 if (offset < section->size_of_raw_data) { |
| 714 return section->virtual_address + offset; | 716 return section->virtual_address + offset; |
| 715 } | 717 } |
| 716 } | 718 } |
| 717 return 0; | 719 return 0; |
| 718 } | 720 } |
| 719 | 721 |
| 720 bool DisassemblerWin32X64::ReadDataDirectory( | 722 bool DisassemblerWin32X64::ReadDataDirectory( |
| 721 int index, | 723 int index, |
| 722 ImageDataDirectory* directory) { | 724 ImageDataDirectory* directory) { |
| 723 | 725 |
| 724 if (index < number_of_data_directories_) { | 726 if (index < number_of_data_directories_) { |
| 725 size_t offset = index * 8 + offset_of_data_directories_; | 727 size_t offset = index * 8 + offset_of_data_directories_; |
| 726 if (offset >= size_of_optional_header_) | 728 if (offset >= size_of_optional_header_) |
| 727 return Bad("number of data directories inconsistent"); | 729 return Bad("number of data directories inconsistent"); |
| 728 const uint8* data_directory = optional_header_ + offset; | 730 const uint8_t* data_directory = optional_header_ + offset; |
| 729 if (data_directory < start() || | 731 if (data_directory < start() || |
| 730 data_directory + 8 >= end()) | 732 data_directory + 8 >= end()) |
| 731 return Bad("data directory outside image"); | 733 return Bad("data directory outside image"); |
| 732 RVA rva = ReadU32(data_directory, 0); | 734 RVA rva = ReadU32(data_directory, 0); |
| 733 size_t size = ReadU32(data_directory, 4); | 735 size_t size = ReadU32(data_directory, 4); |
| 734 if (size > size_of_image_) | 736 if (size > size_of_image_) |
| 735 return Bad("data directory size too big"); | 737 return Bad("data directory size too big"); |
| 736 | 738 |
| 737 // TODO(sra): validate RVA. | 739 // TODO(sra): validate RVA. |
| 738 directory->address_ = rva; | 740 directory->address_ = rva; |
| 739 directory->size_ = static_cast<uint32>(size); | 741 directory->size_ = static_cast<uint32_t>(size); |
| 740 return true; | 742 return true; |
| 741 } else { | 743 } else { |
| 742 directory->address_ = 0; | 744 directory->address_ = 0; |
| 743 directory->size_ = 0; | 745 directory->size_ = 0; |
| 744 return true; | 746 return true; |
| 745 } | 747 } |
| 746 } | 748 } |
| 747 | 749 |
| 748 } // namespace courgette | 750 } // namespace courgette |
| OLD | NEW |