Merge tag 'android-13.0.0_r52' into int/13/fp3

Android 13.0.0 Release 52 (TQ3A.230605.012)

* tag 'android-13.0.0_r52':
  Modify the max size algorithm.

Change-Id: I6b03395fabab93c611cc3534dd9f18d3bb48bbcf
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index bed17e4..3c1eeb8 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -361,6 +361,7 @@
         "offline_files/apk_rorx_unreadable_arm64/*",
         "offline_files/apk_rx_arm64/*",
         "offline_files/apk_rx_unreadable_arm64/*",
+        "offline_files/apk_soname_at_end_arm64/*",
         "offline_files/art_quick_osr_stub_arm/*",
         "offline_files/bad_eh_frame_hdr_arm64/*",
         "offline_files/debug_frame_first_x86/*",
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 0389198..43f1218 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -520,12 +520,33 @@
 void ElfInterfaceImpl<ElfTypes>::GetMaxSize(Memory* memory, uint64_t* size) {
   EhdrType ehdr;
   if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) {
+    *size = 0;
     return;
   }
-  if (ehdr.e_shnum == 0) {
-    return;
+
+  // If this winds up as zero, the PT_LOAD reading will get a better value.
+  uint64_t elf_size = ehdr.e_shoff + ehdr.e_shentsize * ehdr.e_shnum;
+
+  // Search through the PT_LOAD values and if any result in a larger elf
+  // size, use that.
+  uint64_t offset = ehdr.e_phoff;
+  for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
+    PhdrType phdr;
+    if (!memory->ReadFully(offset, &phdr, sizeof(phdr))) {
+      break;
+    }
+    if (phdr.p_type == PT_LOAD) {
+      uint64_t end_offset;
+      if (__builtin_add_overflow(phdr.p_offset, phdr.p_memsz, &end_offset)) {
+        continue;
+      }
+      if (end_offset > elf_size) {
+        elf_size = end_offset;
+      }
+    }
   }
-  *size = ehdr.e_shoff + ehdr.e_shentsize * ehdr.e_shnum;
+
+  *size = elf_size;
 }
 
 template <typename EhdrType, typename ShdrType>
diff --git a/libunwindstack/offline_files/apk_soname_at_end_arm64/libc.so.gz b/libunwindstack/offline_files/apk_soname_at_end_arm64/libc.so.gz
new file mode 100644
index 0000000..7f8b791
--- /dev/null
+++ b/libunwindstack/offline_files/apk_soname_at_end_arm64/libc.so.gz
Binary files differ
diff --git a/libunwindstack/offline_files/apk_soname_at_end_arm64/maps.txt b/libunwindstack/offline_files/apk_soname_at_end_arm64/maps.txt
new file mode 100644
index 0000000..0f17200
--- /dev/null
+++ b/libunwindstack/offline_files/apk_soname_at_end_arm64/maps.txt
@@ -0,0 +1,6 @@
+580e17c000-580e17d000 r--p 0 00:00 0   unwinder
+580e17d000-580e17e000 r-xp 1000 00:00 0   unwinder
+7c0064a000-7c0064b000 r--p a000 00:00 0   unwinder.apk
+7c0064b000-7c0064c000 r-xp b000 00:00 0   unwinder.apk
+7e90877000-7e908ba000 r--p 0 00:00 0   libc.so
+7e908ba000-7e9094c000 r-xp 43000 00:00 0   libc.so
diff --git a/libunwindstack/offline_files/apk_soname_at_end_arm64/output.txt b/libunwindstack/offline_files/apk_soname_at_end_arm64/output.txt
new file mode 100644
index 0000000..557dda7
--- /dev/null
+++ b/libunwindstack/offline_files/apk_soname_at_end_arm64/output.txt
@@ -0,0 +1,3 @@
+  #00 pc 000000000000113c  unwinder.apk!libunwindstack_local.so (offset 0xa000) (WaitForever+60)
+  #01 pc 00000000000010f0  unwinder (main+144)
+  #02 pc 0000000000052cc8  libc.so (__libc_init+104)
diff --git a/libunwindstack/offline_files/apk_soname_at_end_arm64/regs.txt b/libunwindstack/offline_files/apk_soname_at_end_arm64/regs.txt
new file mode 100644
index 0000000..26dc38a
--- /dev/null
+++ b/libunwindstack/offline_files/apk_soname_at_end_arm64/regs.txt
@@ -0,0 +1,34 @@
+x0: 7ff9ec4b94
+x1: 0
+x2: 0
+x3: 0
+x4: 10
+x5: b400007d8087e0c9
+x6: a
+x7: 7f7f7f7f7f7f7f7f
+x8: 1
+x9: fbf40ad8e3dbed37
+x10: 10ec
+x11: 10ec
+x12: 163
+x13: 7ff9ec44c4
+x14: 0
+x15: 2
+x16: 7e9094ec00
+x17: 7e90941e30
+x18: 7e918d4000
+x19: 7c0064b100
+x20: 7e91416000
+x21: 1
+x22: 7ff9ec4c78
+x23: 0
+x24: 0
+x25: 0
+x26: 0
+x27: 0
+x28: 0
+x29: 7ff9ec4ba0
+lr: 7c0064b148
+sp: 7ff9ec4b90
+pc: 7c0064b13c
+pst: 60001000
diff --git a/libunwindstack/offline_files/apk_soname_at_end_arm64/stack.data b/libunwindstack/offline_files/apk_soname_at_end_arm64/stack.data
new file mode 100644
index 0000000..19079b1
--- /dev/null
+++ b/libunwindstack/offline_files/apk_soname_at_end_arm64/stack.data
Binary files differ
diff --git a/libunwindstack/offline_files/apk_soname_at_end_arm64/unwinder.apk.gz b/libunwindstack/offline_files/apk_soname_at_end_arm64/unwinder.apk.gz
new file mode 100644
index 0000000..f38d8f1
--- /dev/null
+++ b/libunwindstack/offline_files/apk_soname_at_end_arm64/unwinder.apk.gz
Binary files differ
diff --git a/libunwindstack/offline_files/apk_soname_at_end_arm64/unwinder.gz b/libunwindstack/offline_files/apk_soname_at_end_arm64/unwinder.gz
new file mode 100644
index 0000000..90eb389
--- /dev/null
+++ b/libunwindstack/offline_files/apk_soname_at_end_arm64/unwinder.gz
Binary files differ
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 0d6fa1d..0306b29 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -1658,5 +1658,32 @@
   VerifyApkRX(unwinder);
 }
 
+TEST_F(UnwindOfflineTest, apk_soname_at_end_arm64) {
+  std::string error_msg;
+  if (!offline_utils_.Init({.offline_files_dir = "apk_soname_at_end_arm64/", .arch = ARCH_ARM64},
+                           &error_msg))
+    FAIL() << error_msg;
+
+  Regs* regs = offline_utils_.GetRegs();
+  std::unique_ptr<Regs> regs_copy(regs->Clone());
+  Unwinder unwinder(128, offline_utils_.GetMaps(), regs, offline_utils_.GetProcessMemory());
+  unwinder.Unwind();
+
+  size_t expected_num_frames;
+  if (!offline_utils_.GetExpectedNumFrames(&expected_num_frames, &error_msg)) FAIL() << error_msg;
+  std::string expected_frame_info;
+  if (!GetExpectedSamplesFrameInfo(&expected_frame_info, &error_msg)) FAIL() << error_msg;
+
+  std::string frame_info(DumpFrames(unwinder));
+  ASSERT_EQ(expected_num_frames, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+  EXPECT_EQ(expected_frame_info, frame_info);
+  EXPECT_EQ(0x7c0064b13cULL, unwinder.frames()[0].pc);
+  EXPECT_EQ(0x7ff9ec4b90ULL, unwinder.frames()[0].sp);
+  EXPECT_EQ(0x580e17d0f0ULL, unwinder.frames()[1].pc);
+  EXPECT_EQ(0x7ff9ec4bb0ULL, unwinder.frames()[1].sp);
+  EXPECT_EQ(0x7e908c9cc8ULL, unwinder.frames()[2].pc);
+  EXPECT_EQ(0x7ff9ec4c10ULL, unwinder.frames()[2].sp);
+}
+
 }  // namespace
 }  // namespace unwindstack