Merge "fastboot: fix build break"
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 725c42c..a0ba81b 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -417,7 +417,7 @@
        "memory map (%zu entr%s):",
        map->size(), map->size() == 1 ? "y" : "ies");
   if (print_fault_address_marker) {
-    if (map->begin() != map->end() && addr < map->begin()->start) {
+    if (map->begin() != map->end() && addr < (*map->begin())->start) {
       _LOG(log, logtype::MAPS, "\n--->Fault address falls at %s before any mapped regions\n",
            get_addr_string(addr).c_str());
       print_fault_address_marker = false;
@@ -429,49 +429,50 @@
   }
 
   std::string line;
-  for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
+  for (auto it = map->begin(); it != map->end(); ++it) {
+    const backtrace_map_t* entry = *it;
     line = "    ";
     if (print_fault_address_marker) {
-      if (addr < it->start) {
+      if (addr < entry->start) {
         _LOG(log, logtype::MAPS, "--->Fault address falls at %s between mapped regions\n",
              get_addr_string(addr).c_str());
         print_fault_address_marker = false;
-      } else if (addr >= it->start && addr < it->end) {
+      } else if (addr >= entry->start && addr < entry->end) {
         line = "--->";
         print_fault_address_marker = false;
       }
     }
-    line += get_addr_string(it->start) + '-' + get_addr_string(it->end - 1) + ' ';
-    if (it->flags & PROT_READ) {
+    line += get_addr_string(entry->start) + '-' + get_addr_string(entry->end - 1) + ' ';
+    if (entry->flags & PROT_READ) {
       line += 'r';
     } else {
       line += '-';
     }
-    if (it->flags & PROT_WRITE) {
+    if (entry->flags & PROT_WRITE) {
       line += 'w';
     } else {
       line += '-';
     }
-    if (it->flags & PROT_EXEC) {
+    if (entry->flags & PROT_EXEC) {
       line += 'x';
     } else {
       line += '-';
     }
-    line += StringPrintf("  %8" PRIxPTR "  %8" PRIxPTR, it->offset, it->end - it->start);
+    line += StringPrintf("  %8" PRIxPTR "  %8" PRIxPTR, entry->offset, entry->end - entry->start);
     bool space_needed = true;
-    if (it->name.length() > 0) {
+    if (entry->name.length() > 0) {
       space_needed = false;
-      line += "  " + it->name;
+      line += "  " + entry->name;
       std::string build_id;
-      if ((it->flags & PROT_READ) && elf_get_build_id(backtrace, it->start, &build_id)) {
+      if ((entry->flags & PROT_READ) && elf_get_build_id(backtrace, entry->start, &build_id)) {
         line += " (BuildId: " + build_id + ")";
       }
     }
-    if (it->load_bias != 0) {
+    if (entry->load_bias != 0) {
       if (space_needed) {
         line += ' ';
       }
-      line += StringPrintf(" (load bias 0x%" PRIxPTR ")", it->load_bias);
+      line += StringPrintf(" (load bias 0x%" PRIxPTR ")", entry->load_bias);
     }
     _LOG(log, logtype::MAPS, "%s\n", line.c_str());
   }
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index b686885..8c8d9f2 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -78,8 +78,8 @@
         return;
     }
 
-    static const char* firmware_dirs[] = {"/etc/firmware/", "/vendor/firmware/",
-                                          "/firmware/image/"};
+    static const char* firmware_dirs[] = {"/etc/firmware/", "/odm/firmware/",
+                                          "/vendor/firmware/", "/firmware/image/"};
 
 try_loading_again:
     for (size_t i = 0; i < arraysize(firmware_dirs); i++) {
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 0e31495..0f1ae11 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -40,9 +40,10 @@
 
 void BacktraceMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
   ScopedBacktraceMapIteratorLock lock(this);
-  for (BacktraceMap::const_iterator it = begin(); it != end(); ++it) {
-    if (addr >= it->start && addr < it->end) {
-      *map = *it;
+  for (auto it = begin(); it != end(); ++it) {
+    const backtrace_map_t* entry = *it;
+    if (addr >= entry->start && addr < entry->end) {
+      *map = *entry;
       return;
     }
   }
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 9ac0a0b..836a774 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -71,8 +71,19 @@
   if (map_info == nullptr) {
     return;
   }
-  unwindstack::Elf* elf = map_info->GetElf(process_memory_, true);
-  map->load_bias = elf->GetLoadBias();
+  map->load_bias = map_info->GetLoadBias(process_memory_);
+}
+
+uint64_t UnwindStackMap::GetLoadBias(size_t index) {
+  if (index >= stack_maps_->Total()) {
+    return 0;
+  }
+
+  unwindstack::MapInfo* map_info = stack_maps_->Get(index);
+  if (map_info == nullptr) {
+    return 0;
+  }
+  return map_info->GetLoadBias(process_memory_);
 }
 
 std::string UnwindStackMap::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index bc432e7..2f63655 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -42,6 +42,8 @@
   const std::shared_ptr<unwindstack::Memory>& process_memory() { return process_memory_; }
 
  protected:
+  uint64_t GetLoadBias(size_t index) override;
+
   std::unique_ptr<unwindstack::Maps> stack_maps_;
   std::shared_ptr<unwindstack::Memory> process_memory_;
 };
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index 0a1f33d..0935660 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -171,10 +171,12 @@
   testdata += android::base::StringPrintf("pid: %d tid: %d\n", getpid(), arg.tid);
   // 2. Dump maps
   for (auto it = map->begin(); it != map->end(); ++it) {
-    testdata += android::base::StringPrintf(
-        "map: start: %" PRIxPTR " end: %" PRIxPTR " offset: %" PRIxPTR " load_bias: %" PRIxPTR
-        " flags: %d name: %s\n",
-        it->start, it->end, it->offset, it->load_bias, it->flags, it->name.c_str());
+    const backtrace_map_t* entry = *it;
+    testdata +=
+        android::base::StringPrintf("map: start: %" PRIxPTR " end: %" PRIxPTR " offset: %" PRIxPTR
+                                    " load_bias: %" PRIxPTR " flags: %d name: %s\n",
+                                    entry->start, entry->end, entry->offset, entry->load_bias,
+                                    entry->flags, entry->name.c_str());
   }
   // 3. Dump registers
   testdata += android::base::StringPrintf("registers: %zu ", sizeof(arg.unw_context));
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 9911e74..890ab3f 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -857,6 +857,34 @@
 
 static bool map_sort(map_test_t i, map_test_t j) { return i.start < j.start; }
 
+static std::string GetTestMapsAsString(const std::vector<map_test_t>& maps) {
+  if (maps.size() == 0) {
+    return "No test map entries\n";
+  }
+  std::string map_txt;
+  for (auto map : maps) {
+    map_txt += android::base::StringPrintf("%" PRIxPTR "-%" PRIxPTR "\n", map.start, map.end);
+  }
+  return map_txt;
+}
+
+static std::string GetMapsAsString(BacktraceMap* maps) {
+  if (maps->size() == 0) {
+    return "No map entries\n";
+  }
+  std::string map_txt;
+  for (const backtrace_map_t* map : *maps) {
+    map_txt += android::base::StringPrintf(
+        "%" PRIxPTR "-%" PRIxPTR " flags: 0x%x offset: 0x%" PRIxPTR " load_bias: 0x%" PRIxPTR,
+        map->start, map->end, map->flags, map->offset, map->load_bias);
+    if (!map->name.empty()) {
+      map_txt += ' ' + map->name;
+    }
+    map_txt += '\n';
+  }
+  return map_txt;
+}
+
 static void VerifyMap(pid_t pid) {
   char buffer[4096];
   snprintf(buffer, sizeof(buffer), "/proc/%d/maps", pid);
@@ -875,12 +903,20 @@
   std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
 
   // Basic test that verifies that the map is in the expected order.
-  ScopedBacktraceMapIteratorLock lock(map.get());
-  std::vector<map_test_t>::const_iterator test_it = test_maps.begin();
-  for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
-    ASSERT_TRUE(test_it != test_maps.end());
-    ASSERT_EQ(test_it->start, it->start);
-    ASSERT_EQ(test_it->end, it->end);
+  auto test_it = test_maps.begin();
+  for (auto it = map->begin(); it != map->end(); ++it) {
+    ASSERT_TRUE(test_it != test_maps.end()) << "Mismatch in number of maps, expected test maps:\n"
+                                            << GetTestMapsAsString(test_maps) << "Actual maps:\n"
+                                            << GetMapsAsString(map.get());
+    ASSERT_EQ(test_it->start, (*it)->start) << "Mismatch in map data, expected test maps:\n"
+                                            << GetTestMapsAsString(test_maps) << "Actual maps:\n"
+                                            << GetMapsAsString(map.get());
+    ASSERT_EQ(test_it->end, (*it)->end) << "Mismatch maps in map data, expected test maps:\n"
+                                        << GetTestMapsAsString(test_maps) << "Actual maps:\n"
+                                        << GetMapsAsString(map.get());
+    // Make sure the load bias get set to a value.
+    ASSERT_NE(static_cast<uint64_t>(-1), (*it)->load_bias) << "Found uninitialized load_bias\n"
+                                                           << GetMapsAsString(map.get());
     ++test_it;
   }
   ASSERT_TRUE(test_it == test_maps.end());
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index d078392..4ae68dd 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -30,6 +30,7 @@
 #endif
 
 #include <deque>
+#include <iterator>
 #include <string>
 #include <vector>
 
@@ -61,6 +62,49 @@
 
   virtual ~BacktraceMap();
 
+  class iterator : public std::iterator<std::bidirectional_iterator_tag, backtrace_map_t*> {
+   public:
+    iterator(BacktraceMap* map, size_t index) : map_(map), index_(index) {}
+
+    iterator& operator++() {
+      index_++;
+      return *this;
+    }
+    iterator& operator++(int increment) {
+      index_ += increment;
+      return *this;
+    }
+    iterator& operator--() {
+      index_--;
+      return *this;
+    }
+    iterator& operator--(int decrement) {
+      index_ -= decrement;
+      return *this;
+    }
+
+    bool operator==(const iterator& rhs) { return this->index_ == rhs.index_; }
+    bool operator!=(const iterator& rhs) { return this->index_ != rhs.index_; }
+
+    const backtrace_map_t* operator*() {
+      if (index_ >= map_->size()) {
+        return nullptr;
+      }
+      backtrace_map_t* map = &map_->maps_[index_];
+      if (map->load_bias == static_cast<uintptr_t>(-1)) {
+        map->load_bias = map_->GetLoadBias(index_);
+      }
+      return map;
+    }
+
+   private:
+    BacktraceMap* map_ = nullptr;
+    size_t index_ = 0;
+  };
+
+  iterator begin() { return iterator(this, 0); }
+  iterator end() { return iterator(this, maps_.size()); }
+
   // Fill in the map data structure for the given address.
   virtual void FillIn(uintptr_t addr, backtrace_map_t* map);
 
@@ -89,14 +133,6 @@
   virtual void LockIterator() {}
   virtual void UnlockIterator() {}
 
-  typedef std::deque<backtrace_map_t>::iterator iterator;
-  iterator begin() { return maps_.begin(); }
-  iterator end() { return maps_.end(); }
-
-  typedef std::deque<backtrace_map_t>::const_iterator const_iterator;
-  const_iterator begin() const { return maps_.begin(); }
-  const_iterator end() const { return maps_.end(); }
-
   size_t size() const { return maps_.size(); }
 
   virtual bool Build();
@@ -114,6 +150,8 @@
  protected:
   BacktraceMap(pid_t pid);
 
+  virtual uint64_t GetLoadBias(size_t /* index */) { return 0; }
+
   virtual bool ParseLine(const char* line, backtrace_map_t* map);
 
   pid_t pid_;
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 75aa427..74930d6 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -118,6 +118,7 @@
         "tests/ElfTestUtils.cpp",
         "tests/LogFake.cpp",
         "tests/MapInfoGetElfTest.cpp",
+        "tests/MapInfoGetLoadBiasTest.cpp",
         "tests/MapsTest.cpp",
         "tests/MemoryBufferTest.cpp",
         "tests/MemoryFake.cpp",
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 97ade56..5f307ed 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -215,4 +215,22 @@
   return interface.release();
 }
 
+uint64_t Elf::GetLoadBias(Memory* memory) {
+  if (!IsValidElf(memory)) {
+    return 0;
+  }
+
+  uint8_t class_type;
+  if (!memory->Read(EI_CLASS, &class_type, 1)) {
+    return 0;
+  }
+
+  if (class_type == ELFCLASS32) {
+    return ElfInterface::GetLoadBias<Elf32_Ehdr, Elf32_Phdr>(memory);
+  } else if (class_type == ELFCLASS64) {
+    return ElfInterface::GetLoadBias<Elf64_Ehdr, Elf64_Phdr>(memory);
+  }
+  return 0;
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 9bdb094..334cf76 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -148,6 +148,26 @@
 }
 
 template <typename EhdrType, typename PhdrType>
+uint64_t ElfInterface::GetLoadBias(Memory* memory) {
+  EhdrType ehdr;
+  if (!memory->Read(0, &ehdr, sizeof(ehdr))) {
+    return false;
+  }
+
+  uint64_t offset = ehdr.e_phoff;
+  for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
+    PhdrType phdr;
+    if (!memory->Read(offset, &phdr, sizeof(phdr))) {
+      return 0;
+    }
+    if (phdr.p_type == PT_LOAD && phdr.p_offset == 0) {
+      return phdr.p_vaddr;
+    }
+  }
+  return 0;
+}
+
+template <typename EhdrType, typename PhdrType>
 bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
   uint64_t offset = ehdr.e_phoff;
   for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
@@ -421,4 +441,7 @@
 template void ElfInterface::GetMaxSizeWithTemplate<Elf32_Ehdr>(Memory*, uint64_t*);
 template void ElfInterface::GetMaxSizeWithTemplate<Elf64_Ehdr>(Memory*, uint64_t*);
 
+template uint64_t ElfInterface::GetLoadBias<Elf32_Ehdr, Elf32_Phdr>(Memory*);
+template uint64_t ElfInterface::GetLoadBias<Elf64_Ehdr, Elf64_Phdr>(Memory*);
+
 }  // namespace unwindstack
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 8a7ad9c..51bce8e 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -121,4 +121,23 @@
   return elf;
 }
 
+uint64_t MapInfo::GetLoadBias(const std::shared_ptr<Memory>& process_memory) {
+  {
+    // Make sure no other thread is trying to add the elf to this map.
+    std::lock_guard<std::mutex> guard(mutex_);
+    if (elf != nullptr) {
+      if (elf->valid()) {
+        return elf->GetLoadBias();
+      } else {
+        return 0;
+      }
+    }
+  }
+
+  // Call lightweight static function that will only read enough of the
+  // elf data to get the load bias.
+  std::unique_ptr<Memory> memory(CreateMemory(process_memory));
+  return Elf::GetLoadBias(memory.get());
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index da2ddc0..d9ea9c4 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -74,6 +74,8 @@
 
   static void GetInfo(Memory* memory, bool* valid, uint64_t* size);
 
+  static uint64_t GetLoadBias(Memory* memory);
+
  protected:
   bool valid_ = false;
   uint64_t load_bias_ = 0;
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index 86e51b3..5cfe74d 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -82,6 +82,9 @@
   DwarfSection* eh_frame() { return eh_frame_.get(); }
   DwarfSection* debug_frame() { return debug_frame_.get(); }
 
+  template <typename EhdrType, typename PhdrType>
+  static uint64_t GetLoadBias(Memory* memory);
+
  protected:
   template <typename AddressType>
   void InitHeadersWithTemplate();
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index e54b348..6f8ceca 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -51,6 +51,8 @@
   // This function guarantees it will never return nullptr.
   Elf* GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata = false);
 
+  uint64_t GetLoadBias(const std::shared_ptr<Memory>& process_memory);
+
  private:
   MapInfo(const MapInfo&) = delete;
   void operator=(const MapInfo&) = delete;
diff --git a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
new file mode 100644
index 0000000..44a73a8
--- /dev/null
+++ b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <elf.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <memory>
+#include <thread>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+
+#include "ElfFake.h"
+#include "ElfTestUtils.h"
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+class MapInfoGetLoadBiasTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    memory_ = new MemoryFake;
+    process_memory_.reset(memory_);
+    elf_ = new ElfFake(new MemoryFake);
+    elf_container_.reset(elf_);
+    map_info_.reset(new MapInfo(0x1000, 0x20000, 0, PROT_READ | PROT_WRITE, ""));
+  }
+
+  void MultipleThreadTest(uint64_t expected_load_bias);
+
+  std::shared_ptr<Memory> process_memory_;
+  MemoryFake* memory_;
+  ElfFake* elf_;
+  std::unique_ptr<ElfFake> elf_container_;
+  std::unique_ptr<MapInfo> map_info_;
+};
+
+TEST_F(MapInfoGetLoadBiasTest, no_elf_and_no_valid_elf_in_memory) {
+  MapInfo info(0x1000, 0x2000, 0, PROT_READ, "");
+
+  EXPECT_EQ(0U, info.GetLoadBias(process_memory_));
+}
+
+TEST_F(MapInfoGetLoadBiasTest, elf_exists) {
+  map_info_->elf = elf_container_.release();
+
+  elf_->FakeSetLoadBias(0);
+  EXPECT_EQ(0U, map_info_->GetLoadBias(process_memory_));
+
+  elf_->FakeSetLoadBias(0x1000);
+  EXPECT_EQ(0x1000U, map_info_->GetLoadBias(process_memory_));
+}
+
+void MapInfoGetLoadBiasTest::MultipleThreadTest(uint64_t expected_load_bias) {
+  static constexpr size_t kNumConcurrentThreads = 100;
+
+  uint64_t load_bias_values[kNumConcurrentThreads];
+  std::vector<std::thread*> threads;
+
+  std::atomic_bool wait;
+  wait = true;
+  // Create all of the threads and have them do the GetLoadBias at the same time
+  // to make it likely that a race will occur.
+  for (size_t i = 0; i < kNumConcurrentThreads; i++) {
+    std::thread* thread = new std::thread([i, this, &wait, &load_bias_values]() {
+      while (wait)
+        ;
+      load_bias_values[i] = map_info_->GetLoadBias(process_memory_);
+    });
+    threads.push_back(thread);
+  }
+
+  // Set them all going and wait for the threads to finish.
+  wait = false;
+  for (auto thread : threads) {
+    thread->join();
+    delete thread;
+  }
+
+  // Now verify that all of the elf files are exactly the same and valid.
+  for (size_t i = 0; i < kNumConcurrentThreads; i++) {
+    EXPECT_EQ(expected_load_bias, load_bias_values[i]) << "Thread " << i << " mismatched.";
+  }
+}
+
+TEST_F(MapInfoGetLoadBiasTest, multiple_thread_elf_exists) {
+  map_info_->elf = elf_container_.release();
+  elf_->FakeSetLoadBias(0x1000);
+
+  MultipleThreadTest(0x1000);
+}
+
+static void InitElfData(MemoryFake* memory, uint64_t offset) {
+  Elf32_Ehdr ehdr;
+  TestInitEhdr(&ehdr, ELFCLASS32, EM_ARM);
+  ehdr.e_phoff = 0x5000;
+  ehdr.e_phnum = 2;
+  ehdr.e_phentsize = sizeof(Elf32_Phdr);
+  memory->SetMemory(offset, &ehdr, sizeof(ehdr));
+
+  Elf32_Phdr phdr;
+  memset(&phdr, 0, sizeof(phdr));
+  phdr.p_type = PT_NULL;
+  memory->SetMemory(offset + 0x5000, &phdr, sizeof(phdr));
+  phdr.p_type = PT_LOAD;
+  phdr.p_offset = 0;
+  phdr.p_vaddr = 0xe000;
+  memory->SetMemory(offset + 0x5000 + sizeof(phdr), &phdr, sizeof(phdr));
+}
+
+TEST_F(MapInfoGetLoadBiasTest, elf_exists_in_memory) {
+  InitElfData(memory_, map_info_->start);
+
+  EXPECT_EQ(0xe000U, map_info_->GetLoadBias(process_memory_));
+}
+
+TEST_F(MapInfoGetLoadBiasTest, multiple_thread_elf_exists_in_memory) {
+  InitElfData(memory_, map_info_->start);
+
+  MultipleThreadTest(0xe000);
+}
+
+}  // namespace unwindstack
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index c22edfe..4d058db 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -7,9 +7,10 @@
 # All binaries gets the same configuration 'legacy'
 dir.legacy = /system
 dir.legacy = /vendor
+dir.legacy = /odm
 dir.legacy = /sbin
 
 [legacy]
 namespace.default.isolated = false
-namespace.default.search.paths = /system/${LIB}:/vendor/${LIB}
-namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}:/data/asan/vendor/${LIB}:/vendor/${LIB}
+namespace.default.search.paths = /system/${LIB}:/vendor/${LIB}:/odm/${LIB}
+namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}:/data/asan/odm/${LIB}:/odm/${LIB}:/data/asan/vendor/${LIB}:/vendor/${LIB}
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 8aa3369..cae6e13 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -6,7 +6,12 @@
 # Don't change the order here.
 dir.system = /system/bin/
 dir.system = /system/xbin/
+dir.vendor = /odm/bin/
 dir.vendor = /vendor/bin/
+dir.vendor = /data/nativetest/odm
+dir.vendor = /data/nativetest64/odm
+dir.vendor = /data/benchmarktest/odm
+dir.vendor = /data/benchmarktest64/odm
 dir.vendor = /data/nativetest/vendor
 dir.vendor = /data/nativetest64/vendor
 dir.vendor = /data/benchmarktest/vendor
@@ -26,8 +31,8 @@
 # can't be loaded in this namespace.
 ###############################################################################
 namespace.default.isolated = false
-namespace.default.search.paths = /system/${LIB}:/vendor/${LIB}
-namespace.default.permitted.paths = /system/${LIB}:/vendor/${LIB}
+namespace.default.search.paths = /system/${LIB}:/odm/${LIB}:/vendor/${LIB}
+namespace.default.permitted.paths = /system/${LIB}:/odm/${LIB}:/vendor/${LIB}
 
 namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}:/data/asan/vendor/${LIB}:/vendor/${LIB}
 namespace.default.asan.permitted.paths = /data/asan/system/${LIB}:/system/${LIB}:/data/asan/vendor/${LIB}:/vendor/${LIB}
@@ -123,6 +128,6 @@
 ###############################################################################
 [vendor]
 namespace.default.isolated = false
-namespace.default.search.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/system/${LIB}/vndk:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/system/${LIB}
+namespace.default.search.paths = /odm/${LIB}/hw:/odm/${LIB}/egl:/odm/${LIB}:/vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/system/${LIB}/vndk:/odm/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/system/${LIB}
 
-namespace.default.asan.search.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/system/${LIB}:/system/${LIB}
+namespace.default.asan.search.paths = /data/asan/odm/${LIB}/hw:/odm/${LIB}/hw:/data/asan/odm/${LIB}/egl:/odm/${LIB}/egl:/data/asan/odm/${LIB}:/odm/${LIB}:/data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/odm/${LIB}/vndk-sp:/odm/${LIB}/vndk-sp:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/system/${LIB}:/system/${LIB}