Courgette: Add static method QuickDetect() to optimize program detection.
Old way: The detection of executables is achieve by allocating an instance of each
Disassembler classes and trying to call ParseHeader() to see if it succeed.
This operation is done many times during FindEmbeddedElements() step,
which takes ~4% of patch generation time.
New way: Using QuickDetect(), which executes only a quick preliminary check,
we avoid useless allocation of Disassembler objects unless
there's a high probability of successfully detecting a valid executable.
This change reduces the execution time of FindEmbeddedElements() by 95%.
BUG=619167
Review-Url: https://codereview.chromium.org/2055343002
Cr-Commit-Position: refs/heads/master@{#404433}
diff --git a/courgette/disassembler_elf_32.cc b/courgette/disassembler_elf_32.cc
index febcdea..a6cb16fa 100644
--- a/courgette/disassembler_elf_32.cc
+++ b/courgette/disassembler_elf_32.cc
@@ -43,14 +43,13 @@
return (*it_)->rva() + (*it_)->relative_target();
}
-DisassemblerElf32::DisassemblerElf32(const void* start, size_t length)
+DisassemblerElf32::DisassemblerElf32(const uint8_t* start, size_t length)
: Disassembler(start, length),
header_(nullptr),
section_header_table_size_(0),
program_header_table_(nullptr),
program_header_table_size_(0),
- default_string_section_(nullptr) {
-}
+ default_string_section_(nullptr) {}
RVA DisassemblerElf32::FileOffsetToRVA(FileOffset offset) const {
// File offsets can be 64-bit values, but we are dealing with 32-bit
@@ -216,6 +215,32 @@
return false;
}
+// static
+bool DisassemblerElf32::QuickDetect(const uint8_t* start,
+ size_t length,
+ e_machine_values elf_em) {
+ if (length < sizeof(Elf32_Ehdr))
+ return false;
+
+ const Elf32_Ehdr* header = reinterpret_cast<const Elf32_Ehdr*>(start);
+
+ // Have magic for ELF header?
+ if (header->e_ident[0] != 0x7f || header->e_ident[1] != 'E' ||
+ header->e_ident[2] != 'L' || header->e_ident[3] != 'F')
+ return false;
+
+ if (header->e_type != ET_EXEC && header->e_type != ET_DYN)
+ return false;
+ if (header->e_machine != elf_em)
+ return false;
+ if (header->e_version != 1)
+ return false;
+ if (header->e_shentsize != sizeof(Elf32_Shdr))
+ return false;
+
+ return true;
+}
+
bool DisassemblerElf32::UpdateLength() {
Elf32_Off result = 0;