Add method to get the address and size of the .text section.

This will be used to speed up JIT lookups, by trivially
skipping JIT entries that don't need to be decompressed.

Test: m libunwindstack_unit_test
Change-Id: I6dabc33de245c0b319c19dbfe1f2129987b42f4b
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 348ffd0..6c9bb8d 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -257,6 +257,24 @@
   return false;
 }
 
+bool Elf::GetTextRange(uint64_t* addr, uint64_t* size) {
+  if (!valid_) {
+    return false;
+  }
+
+  if (interface_->GetTextRange(addr, size)) {
+    *addr += load_bias_;
+    return true;
+  }
+
+  if (gnu_debugdata_interface_ != nullptr && gnu_debugdata_interface_->GetTextRange(addr, size)) {
+    *addr += load_bias_;
+    return true;
+  }
+
+  return false;
+}
+
 ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) {
   if (!IsValidElf(memory)) {
     return nullptr;
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 4eac1fe..54a8f7d 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -69,6 +69,15 @@
   return false;
 }
 
+bool ElfInterface::GetTextRange(uint64_t* addr, uint64_t* size) {
+  if (text_size_ != 0) {
+    *addr = text_addr_;
+    *size = text_size_;
+    return true;
+  }
+  return false;
+}
+
 Memory* ElfInterface::CreateGnuDebugdataMemory() {
   if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) {
     return nullptr;
@@ -366,7 +375,7 @@
       }
       symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize,
                                      str_shdr.sh_offset, str_shdr.sh_size));
-    } else if (shdr.sh_type == SHT_PROGBITS && sec_size != 0) {
+    } else if ((shdr.sh_type == SHT_PROGBITS || shdr.sh_type == SHT_NOBITS) && sec_size != 0) {
       // Look for the .debug_frame and .gnu_debugdata.
       if (shdr.sh_name < sec_size) {
         std::string name;
@@ -394,6 +403,9 @@
               data_vaddr_start_ = 0;
               data_vaddr_end_ = 0;
             }
+          } else if (name == ".text") {
+            text_addr_ = shdr.sh_addr;
+            text_size_ = shdr.sh_size;
           }
         }
       }
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index e15b221..9961a65 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -71,6 +71,8 @@
 
   bool IsValidPc(uint64_t pc);
 
+  bool GetTextRange(uint64_t* addr, uint64_t* size);
+
   void GetLastError(ErrorData* data);
   ErrorCode GetLastErrorCode();
   uint64_t GetLastErrorAddress();
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index 817fa6a..598b7d1 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -89,6 +89,8 @@
 
   virtual bool IsValidPc(uint64_t pc);
 
+  bool GetTextRange(uint64_t* addr, uint64_t* size);
+
   Memory* CreateGnuDebugdataMemory();
 
   Memory* memory() { return memory_; }
@@ -163,6 +165,9 @@
   uint64_t gnu_build_id_offset_ = 0;
   uint64_t gnu_build_id_size_ = 0;
 
+  uint64_t text_addr_ = 0;
+  uint64_t text_size_ = 0;
+
   uint8_t soname_type_ = SONAME_UNKNOWN;
   std::string soname_;
 
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
index c8134fd..15c9a32 100644
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ b/libunwindstack/tests/JitDebugTest.cpp
@@ -97,7 +97,7 @@
     ehdr.e_shstrndx = 1;
     ehdr.e_shoff = sh_offset;
     ehdr.e_shentsize = sizeof(ShdrType);
-    ehdr.e_shnum = 3;
+    ehdr.e_shnum = 4;
     memory_->SetMemory(offset, &ehdr, sizeof(ehdr));
 
     ShdrType shdr;
@@ -113,6 +113,7 @@
     shdr.sh_size = 0x100;
     memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
     memory_->SetMemory(offset + 0x500, ".debug_frame");
+    memory_->SetMemory(offset + 0x550, ".text");
 
     sh_offset += sizeof(shdr);
     memset(&shdr, 0, sizeof(shdr));
@@ -123,6 +124,15 @@
     shdr.sh_size = 0x200;
     memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
 
+    sh_offset += sizeof(shdr);
+    memset(&shdr, 0, sizeof(shdr));
+    shdr.sh_type = SHT_NOBITS;
+    shdr.sh_name = 0x50;
+    shdr.sh_addr = pc;
+    shdr.sh_offset = 0;
+    shdr.sh_size = size;
+    memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
+
     // Now add a single cie/fde.
     uint64_t dwarf_offset = offset + 0x600;
     if (class_type == ELFCLASS32) {
@@ -295,6 +305,11 @@
 
   Elf* elf = jit_debug_->Find(maps_.get(), 0x1500);
   ASSERT_TRUE(elf != nullptr);
+  uint64_t text_addr;
+  uint64_t text_size;
+  ASSERT_TRUE(elf->GetTextRange(&text_addr, &text_size));
+  ASSERT_EQ(text_addr, 0x1500u);
+  ASSERT_EQ(text_size, 0x200u);
 
   // Clear the memory and verify all of the data is cached.
   memory_->Clear();