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

Commit b211c877 authored by Christopher Ferris's avatar Christopher Ferris Committed by android-build-merger
Browse files

Merge "Fix offsets when shared lib split across maps."

am: 1baa19b1

Change-Id: I05884b4b1dbd604c4c2bdec961bf51c376ef6ba1
parents 87cb715d 1baa19b1
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -117,7 +117,7 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
    back_frame->map.name = frame->map_name;
    back_frame->map.start = frame->map_start;
    back_frame->map.end = frame->map_end;
    back_frame->map.offset = frame->map_offset;
    back_frame->map.offset = frame->map_elf_start_offset;
    back_frame->map.load_bias = frame->map_load_bias;
    back_frame->map.flags = frame->map_flags;
  }
+37 −48
Original line number Diff line number Diff line
@@ -32,34 +32,28 @@ 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.
  for (auto iter = maps_->begin(); iter != maps_->end(); ++iter) {
    if (*iter == this) {
      if (iter == maps_->begin()) {
        return false;
      }
      --iter;
      MapInfo* prev_map = *iter;
      // Make sure this is a read-only map.
      if (prev_map->flags != PROT_READ) {
  if (prev_map == nullptr || prev_map->flags != PROT_READ) {
    return false;
  }

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

  uint64_t max_size;
  if (!Elf::GetInfo(memory, &max_size) || max_size < map_size) {
    return false;
  }

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

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

Memory* MapInfo::GetFileMemory() {
  std::unique_ptr<MemoryFileAtOffset> memory(new MemoryFileAtOffset);
@@ -91,14 +85,13 @@ Memory* MapInfo::GetFileMemory() {

  // Check if the start of this map is an embedded elf.
  uint64_t max_size = 0;
  uint64_t file_offset = offset;
  if (Elf::GetInfo(memory.get(), &max_size)) {
    if (max_size > map_size) {
      if (memory->Init(name, file_offset, max_size)) {
      if (memory->Init(name, offset, max_size)) {
        return memory.release();
      }
      // Try to reinit using the default map_size.
      if (memory->Init(name, file_offset, map_size)) {
      if (memory->Init(name, offset, map_size)) {
        return memory.release();
      }
      return nullptr;
@@ -109,6 +102,13 @@ Memory* MapInfo::GetFileMemory() {
  // No elf at offset, try to init as if the whole file is an elf.
  if (memory->Init(name, 0) && Elf::IsValidElf(memory.get())) {
    elf_offset = offset;
    // 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) {
      elf_start_offset = offset;
    }
    return memory.release();
  }

@@ -156,35 +156,24 @@ Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) {
    return memory.release();
  }

  if (name.empty() || maps_ == nullptr) {
    return nullptr;
  }

  // Find the read-only map by looking at the previous map. The linker
  // 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.
  MapInfo* ro_map_info = nullptr;
  for (auto iter = maps_->begin(); iter != maps_->end(); ++iter) {
    if (*iter == this) {
      if (iter != maps_->begin()) {
        --iter;
        ro_map_info = *iter;
      }
      break;
    }
  }

  if (ro_map_info == nullptr || ro_map_info->name != name || ro_map_info->offset >= offset) {
  if (offset == 0 || name.empty() || prev_map == nullptr || prev_map->name != name ||
      prev_map->offset >= offset) {
    return nullptr;
  }

  // Make sure that relative pc values are corrected properly.
  elf_offset = offset - ro_map_info->offset;
  elf_offset = offset - prev_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;

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

  return ranges;
+13 −3
Original line number Diff line number Diff line
@@ -67,13 +67,15 @@ bool Maps::Parse() {
        if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
          flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
        }
        maps_.push_back(new MapInfo(this, start, end, pgoff, flags, name));
        maps_.push_back(
            new MapInfo(maps_.empty() ? nullptr : maps_.back(), start, end, pgoff, flags, name));
      });
}

void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
               const std::string& name, uint64_t load_bias) {
  MapInfo* map_info = new MapInfo(this, start, end, offset, flags, name);
  MapInfo* map_info =
      new MapInfo(maps_.empty() ? nullptr : maps_.back(), start, end, offset, flags, name);
  map_info->load_bias = load_bias;
  maps_.push_back(map_info);
}
@@ -81,6 +83,13 @@ void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
void Maps::Sort() {
  std::sort(maps_.begin(), maps_.end(),
            [](const MapInfo* a, const MapInfo* b) { return a->start < b->start; });

  // Set the prev_map values on the info objects.
  MapInfo* prev_map = nullptr;
  for (MapInfo* map_info : maps_) {
    map_info->prev_map = prev_map;
    prev_map = map_info;
  }
}

Maps::~Maps() {
@@ -98,7 +107,8 @@ bool BufferMaps::Parse() {
        if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
          flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
        }
        maps_.push_back(new MapInfo(this, start, end, pgoff, flags, name));
        maps_.push_back(
            new MapInfo(maps_.empty() ? nullptr : maps_.back(), start, end, pgoff, flags, name));
      });
}

+9 −6
Original line number Diff line number Diff line
@@ -59,7 +59,8 @@ void Unwinder::FillInDexFrame() {
  if (info != nullptr) {
    frame->map_start = info->start;
    frame->map_end = info->end;
    frame->map_offset = info->offset;
    frame->map_elf_start_offset = info->elf_start_offset;
    frame->map_exact_offset = info->offset;
    frame->map_load_bias = info->load_bias;
    frame->map_flags = info->flags;
    if (resolve_names_) {
@@ -102,7 +103,8 @@ void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_
  if (resolve_names_) {
    frame->map_name = map_info->name;
  }
  frame->map_offset = map_info->offset;
  frame->map_elf_start_offset = map_info->elf_start_offset;
  frame->map_exact_offset = map_info->offset;
  frame->map_start = map_info->start;
  frame->map_end = map_info->end;
  frame->map_flags = map_info->flags;
@@ -290,10 +292,6 @@ std::string Unwinder::FormatFrame(const FrameData& frame, bool is32bit) {
    data += android::base::StringPrintf("  #%02zu pc %016" PRIx64, frame.num, frame.rel_pc);
  }

  if (frame.map_offset != 0) {
    data += android::base::StringPrintf(" (offset 0x%" PRIx64 ")", frame.map_offset);
  }

  if (frame.map_start == frame.map_end) {
    // No valid map associated with this frame.
    data += "  <unknown>";
@@ -302,6 +300,11 @@ std::string Unwinder::FormatFrame(const FrameData& frame, bool is32bit) {
  } else {
    data += android::base::StringPrintf("  <anonymous:%" PRIx64 ">", frame.map_start);
  }

  if (frame.map_elf_start_offset != 0) {
    data += android::base::StringPrintf(" (offset 0x%" PRIx64 ")", frame.map_elf_start_offset);
  }

  if (!frame.function_name.empty()) {
    data += " (" + frame.function_name;
    if (frame.function_offset != 0) {
+14 −17
Original line number Diff line number Diff line
@@ -25,38 +25,31 @@
#include <string>

#include <unwindstack/Elf.h>
#include <unwindstack/Memory.h>

namespace unwindstack {

// Forward declarations.
class Maps;
class Memory;

struct MapInfo {
  MapInfo(Maps* maps) : maps_(maps) {}
  MapInfo(Maps* maps, uint64_t start, uint64_t end) : maps_(maps), start(start), end(end) {}
  MapInfo(Maps* maps, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
  MapInfo(MapInfo* map_info, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
          const char* name)
      : maps_(maps),
        start(start),
      : start(start),
        end(end),
        offset(offset),
        flags(flags),
        name(name),
        prev_map(map_info),
        load_bias(static_cast<uint64_t>(-1)) {}
  MapInfo(Maps* maps, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
  MapInfo(MapInfo* map_info, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
          const std::string& name)
      : maps_(maps),
        start(start),
      : start(start),
        end(end),
        offset(offset),
        flags(flags),
        name(name),
        prev_map(map_info),
        load_bias(static_cast<uint64_t>(-1)) {}
  ~MapInfo() = default;

  Maps* maps_ = nullptr;

  uint64_t start = 0;
  uint64_t end = 0;
  uint64_t offset = 0;
@@ -64,10 +57,14 @@ struct MapInfo {
  std::string name;
  std::shared_ptr<Elf> elf;
  // This value is only non-zero if the offset is non-zero but there is
  // no elf signature found at that offset. This indicates that the
  // entire file is represented by the Memory object returned by CreateMemory,
  // instead of a portion of the file.
  // no elf signature found at that offset.
  uint64_t elf_offset = 0;
  // This value is the offset from the map in memory that is the start
  // of the elf. This is not equal to offset when the linker splits
  // shared libraries into a read-only and read-execute map.
  uint64_t elf_start_offset = 0;

  MapInfo* prev_map = nullptr;

  std::atomic_uint64_t load_bias;

Loading