Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8bf4e29e authored by Christopher Ferris's avatar Christopher Ferris Committed by Gerrit Code Review
Browse files

Merge "Properly handle empty map after read-only map."

parents f8c0350e 0f40a053
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -240,6 +240,7 @@ cc_defaults {
        "tests/files/offline/debug_frame_load_bias_arm/*",
        "tests/files/offline/eh_frame_bias_x86/*",
        "tests/files/offline/eh_frame_hdr_begin_x86_64/*",
        "tests/files/offline/empty_arm64/*",
        "tests/files/offline/invalid_elf_offset_arm/*",
        "tests/files/offline/jit_debug_arm/*",
        "tests/files/offline/jit_debug_x86/*",
+20 −20
Original line number Diff line number Diff line
@@ -37,12 +37,12 @@ namespace unwindstack {
bool MapInfo::InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory) {
  // One last attempt, see if the previous map is read-only with the
  // same name and stretches across this map.
  if (prev_map == nullptr || prev_map->flags != PROT_READ) {
  if (prev_real_map == nullptr || prev_real_map->flags != PROT_READ) {
    return false;
  }

  uint64_t map_size = end - prev_map->end;
  if (!memory->Init(name, prev_map->offset, map_size)) {
  uint64_t map_size = end - prev_real_map->end;
  if (!memory->Init(name, prev_real_map->offset, map_size)) {
    return false;
  }

@@ -51,12 +51,12 @@ bool MapInfo::InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory)
    return false;
  }

  if (!memory->Init(name, prev_map->offset, max_size)) {
  if (!memory->Init(name, prev_real_map->offset, max_size)) {
    return false;
  }

  elf_offset = offset - prev_map->offset;
  elf_start_offset = prev_map->offset;
  elf_offset = offset - prev_real_map->offset;
  elf_start_offset = prev_real_map->offset;
  return true;
}

@@ -112,8 +112,8 @@ Memory* MapInfo::GetFileMemory() {
    // Need to check how to set the elf start offset. If this map is not
    // the r-x map of a r-- map, then use the real offset value. Otherwise,
    // use 0.
    if (prev_map == nullptr || prev_map->offset != 0 || prev_map->flags != PROT_READ ||
        prev_map->name != name) {
    if (prev_real_map == nullptr || prev_real_map->offset != 0 ||
        prev_real_map->flags != PROT_READ || prev_real_map->name != name) {
      elf_start_offset = offset;
    }
    return memory.release();
@@ -172,20 +172,20 @@ Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) {
  // doesn't guarantee that this invariant will always be true. However,
  // if that changes, there is likely something else that will change and
  // break something.
  if (offset == 0 || name.empty() || prev_map == nullptr || prev_map->name != name ||
      prev_map->offset >= offset) {
  if (offset == 0 || name.empty() || prev_real_map == nullptr || prev_real_map->name != name ||
      prev_real_map->offset >= offset) {
    return nullptr;
  }

  // Make sure that relative pc values are corrected properly.
  elf_offset = offset - prev_map->offset;
  elf_offset = offset - prev_real_map->offset;
  // Use this as the elf start offset, otherwise, you always get offsets into
  // the r-x section, which is not quite the right information.
  elf_start_offset = prev_map->offset;
  elf_start_offset = prev_real_map->offset;

  MemoryRanges* ranges = new MemoryRanges;
  ranges->Insert(
      new MemoryRange(process_memory, prev_map->start, prev_map->end - prev_map->start, 0));
  ranges->Insert(new MemoryRange(process_memory, prev_real_map->start,
                                 prev_real_map->end - prev_real_map->start, 0));
  ranges->Insert(new MemoryRange(process_memory, start, end - start, elf_offset));

  memory_backed_elf = true;
@@ -236,15 +236,15 @@ Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum exp

  if (!elf->valid()) {
    elf_start_offset = offset;
  } else if (prev_map != nullptr && elf_start_offset != offset &&
             prev_map->offset == elf_start_offset && prev_map->name == name) {
  } else if (prev_real_map != nullptr && elf_start_offset != offset &&
             prev_real_map->offset == elf_start_offset && prev_real_map->name == name) {
    // If there is a read-only map then a read-execute map that represents the
    // same elf object, make sure the previous map is using the same elf
    // object if it hasn't already been set.
    std::lock_guard<std::mutex> guard(prev_map->mutex_);
    if (prev_map->elf.get() == nullptr) {
      prev_map->elf = elf;
      prev_map->memory_backed_elf = memory_backed_elf;
    std::lock_guard<std::mutex> guard(prev_real_map->mutex_);
    if (prev_real_map->elf.get() == nullptr) {
      prev_real_map->elf = elf;
      prev_real_map->memory_backed_elf = memory_backed_elf;
    }
  }
  return elf.get();
+26 −8
Original line number Diff line number Diff line
@@ -60,6 +60,8 @@ MapInfo* Maps::Find(uint64_t pc) {
}

bool Maps::Parse() {
  MapInfo* prev_map = nullptr;
  MapInfo* prev_real_map = nullptr;
  return android::procinfo::ReadMapFile(
      GetMapsFile(),
      [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t, const char* name) {
@@ -67,17 +69,24 @@ bool Maps::Parse() {
        if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
          flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
        }
        maps_.emplace_back(
            new MapInfo(maps_.empty() ? nullptr : maps_.back().get(), start, end, pgoff,
                        flags, name));
        maps_.emplace_back(new MapInfo(prev_map, prev_real_map, start, end, pgoff, flags, name));
        prev_map = maps_.back().get();
        if (!prev_map->IsBlank()) {
          prev_real_map = prev_map;
        }
      });
}

void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
               const std::string& name, uint64_t load_bias) {
  MapInfo* prev_map = maps_.empty() ? nullptr : maps_.back().get();
  MapInfo* prev_real_map = prev_map;
  while (prev_real_map != nullptr && prev_real_map->IsBlank()) {
    prev_real_map = prev_real_map->prev_map;
  }

  auto map_info =
      std::make_unique<MapInfo>(maps_.empty() ? nullptr : maps_.back().get(), start, end, offset,
                                flags, name);
      std::make_unique<MapInfo>(prev_map, prev_real_map, start, end, offset, flags, name);
  map_info->load_bias = load_bias;
  maps_.emplace_back(std::move(map_info));
}
@@ -89,14 +98,21 @@ void Maps::Sort() {

  // Set the prev_map values on the info objects.
  MapInfo* prev_map = nullptr;
  MapInfo* prev_real_map = nullptr;
  for (const auto& map_info : maps_) {
    map_info->prev_map = prev_map;
    map_info->prev_real_map = prev_real_map;
    prev_map = map_info.get();
    if (!prev_map->IsBlank()) {
      prev_real_map = prev_map;
    }
  }
}

bool BufferMaps::Parse() {
  std::string content(buffer_);
  MapInfo* prev_map = nullptr;
  MapInfo* prev_real_map = nullptr;
  return android::procinfo::ReadMapFileContent(
      &content[0],
      [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t, const char* name) {
@@ -104,9 +120,11 @@ bool BufferMaps::Parse() {
        if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
          flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
        }
        maps_.emplace_back(
            new MapInfo(maps_.empty() ? nullptr : maps_.back().get(), start, end, pgoff,
                        flags, name));
        maps_.emplace_back(new MapInfo(prev_map, prev_real_map, start, end, pgoff, flags, name));
        prev_map = maps_.back().get();
        if (!prev_map->IsBlank()) {
          prev_real_map = prev_map;
        }
      });
}

+18 −6
Original line number Diff line number Diff line
@@ -31,24 +31,26 @@ namespace unwindstack {
class MemoryFileAtOffset;

struct MapInfo {
  MapInfo(MapInfo* map_info, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
          const char* name)
  MapInfo(MapInfo* prev_map, MapInfo* prev_real_map, uint64_t start, uint64_t end, uint64_t offset,
          uint64_t flags, const char* name)
      : start(start),
        end(end),
        offset(offset),
        flags(flags),
        name(name),
        prev_map(map_info),
        prev_map(prev_map),
        prev_real_map(prev_real_map),
        load_bias(INT64_MAX),
        build_id(0) {}
  MapInfo(MapInfo* map_info, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
          const std::string& name)
  MapInfo(MapInfo* prev_map, MapInfo* prev_real_map, uint64_t start, uint64_t end, uint64_t offset,
          uint64_t flags, const std::string& name)
      : start(start),
        end(end),
        offset(offset),
        flags(flags),
        name(name),
        prev_map(map_info),
        prev_map(prev_map),
        prev_real_map(prev_real_map),
        load_bias(INT64_MAX),
        build_id(0) {}
  ~MapInfo();
@@ -71,6 +73,14 @@ struct MapInfo {
  uint64_t elf_start_offset = 0;

  MapInfo* prev_map = nullptr;
  // This is the previous map that is not empty with a 0 offset. For
  // example, this set of maps:
  //  1000-2000  r--p 000000 00:00 0 libc.so
  //  2000-3000  ---p 000000 00:00 0 libc.so
  //  3000-4000  r-xp 003000 00:00 0 libc.so
  // The last map's prev_map would point to the 2000-3000 map, while the
  // prev_real_map would point to the 1000-2000 map.
  MapInfo* prev_real_map = nullptr;

  std::atomic_int64_t load_bias;

@@ -97,6 +107,8 @@ struct MapInfo {
  // Returns the printable version of the build id (hex dump of raw data).
  std::string GetPrintableBuildID();

  inline bool IsBlank() { return offset == 0 && flags == 0 && name.empty(); }

 private:
  MapInfo(const MapInfo&) = delete;
  void operator=(const MapInfo&) = delete;
+8 −8
Original line number Diff line number Diff line
@@ -105,7 +105,7 @@ TEST(DexFileTest, create_using_file) {
            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));

  MemoryFake memory;
  MapInfo info(nullptr, 0, 0x10000, 0, 0x5, tf.path);
  MapInfo info(nullptr, nullptr, 0, 0x10000, 0, 0x5, tf.path);
  EXPECT_TRUE(DexFile::Create(0x500, &memory, &info) != nullptr);
}

@@ -118,7 +118,7 @@ TEST(DexFileTest, create_using_file_non_zero_start) {
            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));

  MemoryFake memory;
  MapInfo info(nullptr, 0x100, 0x10000, 0, 0x5, tf.path);
  MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0, 0x5, tf.path);
  EXPECT_TRUE(DexFile::Create(0x600, &memory, &info) != nullptr);
}

@@ -131,21 +131,21 @@ TEST(DexFileTest, create_using_file_non_zero_offset) {
            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));

  MemoryFake memory;
  MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, tf.path);
  MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, tf.path);
  EXPECT_TRUE(DexFile::Create(0x400, &memory, &info) != nullptr);
}

TEST(DexFileTest, create_using_memory_empty_file) {
  MemoryFake memory;
  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
  MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, "");
  MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, "");
  EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr);
}

TEST(DexFileTest, create_using_memory_file_does_not_exist) {
  MemoryFake memory;
  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
  MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
  MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
  EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr);
}

@@ -158,7 +158,7 @@ TEST(DexFileTest, create_using_memory_file_is_malformed) {

  MemoryFake memory;
  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
  MapInfo info(nullptr, 0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
  MapInfo info(nullptr, nullptr, 0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
  std::unique_ptr<DexFile> dex_file = DexFile::Create(0x4000, &memory, &info);
  ASSERT_TRUE(dex_file != nullptr);

@@ -171,7 +171,7 @@ TEST(DexFileTest, create_using_memory_file_is_malformed) {
TEST(DexFileTest, get_method) {
  MemoryFake memory;
  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
  MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, "");
  MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, "");
  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
  ASSERT_TRUE(dex_file != nullptr);

@@ -189,7 +189,7 @@ TEST(DexFileTest, get_method) {
TEST(DexFileTest, get_method_empty) {
  MemoryFake memory;
  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
  MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, "");
  MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, "");
  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
  ASSERT_TRUE(dex_file != nullptr);

Loading