Added a TypedRVA to track what kind of branch instruction is used for
the jump and compute the target RVA accordingly.  Also updated the
unit test to use TypedRVA and check that only X86 RVAs are found by
the X86 "disassembler".

BUG=258645

Review URL: https://chromiumcodereview.appspot.com/18055007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@213220 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/courgette/disassembler_elf_32.cc b/courgette/disassembler_elf_32.cc
index 91ccd45..1033fd28 100644
--- a/courgette/disassembler_elf_32.cc
+++ b/courgette/disassembler_elf_32.cc
@@ -10,6 +10,7 @@
 
 #include "base/basictypes.h"
 #include "base/logging.h"
+#include "base/memory/scoped_vector.h"
 
 #include "courgette/assembly_program.h"
 #include "courgette/courgette.h"
@@ -203,7 +204,7 @@
 }
 
 CheckBool DisassemblerElf32::RVAsToOffsets(std::vector<RVA>* rvas,
-                                              std::vector<size_t>* offsets) {
+                                           std::vector<size_t>* offsets) {
   offsets->clear();
 
   for (std::vector<RVA>::iterator rva = rvas->begin();
@@ -221,24 +222,39 @@
   return true;
 }
 
+CheckBool DisassemblerElf32::RVAsToOffsets(ScopedVector<TypedRVA>* rvas) {
+  for (ScopedVector<TypedRVA>::iterator rva = rvas->begin();
+       rva != rvas->end();
+       rva++) {
+
+    size_t offset;
+
+    if (!RVAToFileOffset((*rva)->rva(), &offset))
+      return false;
+
+    (*rva)->set_offset(offset);
+  }
+
+  return true;
+}
+
 CheckBool DisassemblerElf32::ParseFile(AssemblyProgram* program) {
   // Walk all the bytes in the file, whether or not in a section.
   uint32 file_offset = 0;
 
   std::vector<size_t> abs_offsets;
-  std::vector<size_t> rel_offsets;
 
   if (!RVAsToOffsets(&abs32_locations_, &abs_offsets))
     return false;
 
-  if (!RVAsToOffsets(&rel32_locations_, &rel_offsets))
+  if (!RVAsToOffsets(&rel32_locations_))
     return false;
 
   std::vector<size_t>::iterator current_abs_offset = abs_offsets.begin();
-  std::vector<size_t>::iterator current_rel_offset = rel_offsets.begin();
+  ScopedVector<TypedRVA>::iterator current_rel = rel32_locations_.begin();
 
   std::vector<size_t>::iterator end_abs_offset = abs_offsets.end();
-  std::vector<size_t>::iterator end_rel_offset = rel_offsets.end();
+  ScopedVector<TypedRVA>::iterator end_rel = rel32_locations_.end();
 
   for (int section_id = 0;
        section_id < SectionHeaderCount();
@@ -261,7 +277,7 @@
       case SHT_PROGBITS:
         if (!ParseProgbitsSection(section_header,
                                   &current_abs_offset, end_abs_offset,
-                                  &current_rel_offset, end_rel_offset,
+                                  &current_rel, end_rel,
                                   program))
           return false;
         file_offset = section_header->sh_offset + section_header->sh_size;
@@ -306,8 +322,8 @@
     const Elf32_Shdr *section_header,
     std::vector<size_t>::iterator* current_abs_offset,
     std::vector<size_t>::iterator end_abs_offset,
-    std::vector<size_t>::iterator* current_rel_offset,
-    std::vector<size_t>::iterator end_rel_offset,
+    ScopedVector<TypedRVA>::iterator* current_rel,
+    ScopedVector<TypedRVA>::iterator end_rel,
     AssemblyProgram* program) {
 
   // Walk all the bytes in the file, whether or not in a section.
@@ -325,9 +341,9 @@
         file_offset > **current_abs_offset)
       return false;
 
-    while (*current_rel_offset != end_rel_offset &&
-           file_offset > **current_rel_offset) {
-      (*current_rel_offset)++;
+    while (*current_rel != end_rel &&
+           file_offset > (**current_rel)->get_offset()) {
+      (*current_rel)++;
     }
 
     size_t next_relocation = section_end;
@@ -339,9 +355,9 @@
     // Rel offsets are heuristically derived, and might (incorrectly) overlap
     // an Abs value, or the end of the section, so +3 to make sure there is
     // room for the full 4 byte value.
-    if (*current_rel_offset != end_rel_offset &&
-        next_relocation > (**current_rel_offset + 3))
-      next_relocation = **current_rel_offset;
+    if (*current_rel != end_rel &&
+        next_relocation > ((**current_rel)->get_offset() + 3))
+      next_relocation = (**current_rel)->get_offset();
 
     if (next_relocation > file_offset) {
       if (!ParseSimpleRegion(file_offset, next_relocation, program))
@@ -364,20 +380,19 @@
       continue;
     }
 
-    if (*current_rel_offset != end_rel_offset &&
-        file_offset == **current_rel_offset) {
+    if (*current_rel != end_rel &&
+        file_offset == (**current_rel)->get_offset()) {
 
-      const uint8* p = OffsetToPointer(file_offset);
-      uint32 relative_target = Read32LittleEndian(p);
+      uint32 relative_target = (**current_rel)->relative_target();
       // This cast is for 64 bit systems, and is only safe because we
       // are working on 32 bit executables.
       RVA target_rva = (RVA)(origin + (file_offset - origin_offset) +
-                             4 + relative_target);
+                             relative_target);
 
       if (!program->EmitRel32(program->FindOrMakeRel32Label(target_rva)))
         return false;
       file_offset += sizeof(RVA);
-      (*current_rel_offset)++;
+      (*current_rel)++;
       continue;
     }
   }
@@ -482,7 +497,9 @@
       return false;
   }
 
-  std::sort(rel32_locations_.begin(), rel32_locations_.end());
+  std::sort(rel32_locations_.begin(),
+            rel32_locations_.end(),
+            TypedRVA::IsLessThan);
   return true;
 }