arm_cfi_table_unittest.cc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/profiler/arm_cfi_table.h"
  5. #include "testing/gtest/include/gtest/gtest.h"
  6. #include "third_party/abseil-cpp/absl/types/optional.h"
  7. namespace base {
  8. bool operator==(const ArmCFITable::FrameEntry& a,
  9. const ArmCFITable::FrameEntry& b) {
  10. return a.cfa_offset == b.cfa_offset && a.ra_offset == b.ra_offset;
  11. }
  12. TEST(ArmCFITableTest, Parse) {
  13. auto parse_cfi = [](std::vector<uint16_t> data) {
  14. return ArmCFITable::Parse(
  15. {reinterpret_cast<const uint8_t*>(data.data()), data.size() * 2});
  16. };
  17. auto reader = parse_cfi({0x01, 0x00, 0x0, 0x0, 0xffff});
  18. EXPECT_TRUE(reader);
  19. EXPECT_EQ(1U, reader->GetTableSizeForTesting());
  20. }
  21. TEST(ArmCFITableTest, FindEntryForAddress) {
  22. // Input is generated from the CFI file:
  23. // STACK CFI INIT 1000 500
  24. // STACK CFI 1002 .cfa: sp 272 + .ra: .cfa -4 + ^ r4: .cfa -16 +
  25. // STACK CFI 1008 .cfa: sp 544 + .r1: .cfa -0 + ^ r4: .cfa -16 + ^
  26. // STACK CFI 1040 .cfa: sp 816 + .r1: .cfa -0 + ^ r4: .cfa -16 + ^
  27. // STACK CFI 1050 .cfa: sp 816 + .ra: .cfa -8 + ^ r4: .cfa -16 + ^
  28. // STACK CFI 1080 .cfa: sp 544 + .r1: .cfa -0 + ^ r4: .cfa -16 + ^
  29. //
  30. // STACK CFI INIT 2000 22
  31. // STACK CFI 2004 .cfa: sp 16 + .ra: .cfa -12 + ^ r4: .cfa -16 + ^
  32. // STACK CFI 2008 .cfa: sp 16 + .ra: .cfa -12 + ^ r4: .cfa -16 + ^
  33. //
  34. // STACK CFI INIT 2024 100
  35. // STACK CFI 2030 .cfa: sp 48 + .ra: .cfa -12 + ^ r4: .cfa -16 + ^
  36. // STACK CFI 2100 .cfa: sp 64 + .r1: .cfa -0 + ^ r4: .cfa -16 + ^
  37. //
  38. // STACK CFI INIT 2200 10
  39. // STACK CFI 2204 .cfa: sp 44 + .ra: .cfa -8 + ^ r4: .cfa -16 + ^
  40. const uint16_t input_data[] = {// UNW_INDEX size
  41. 0x07, 0x0,
  42. // UNW_INDEX function_addresses (4 byte rows).
  43. 0x1000, 0x0, 0x1502, 0x0, 0x2000, 0x0, 0x2024,
  44. 0x0, 0x2126, 0x0, 0x2200, 0x0, 0x2212, 0x0,
  45. // UNW_INDEX entry_data_indices (2 byte rows).
  46. 0x0, 0xffff, 0xb, 0x10, 0xffff, 0x15, 0xffff,
  47. // UNW_DATA table.
  48. 0x5, 0x2, 0x111, 0x8, 0x220, 0x40, 0x330, 0x50,
  49. 0x332, 0x80, 0x220, 0x2, 0x4, 0x13, 0x8, 0x13,
  50. 0x2, 0xc, 0x33, 0xdc, 0x40, 0x1, 0x4, 0x2e};
  51. auto reader = ArmCFITable::Parse(
  52. {reinterpret_cast<const uint8_t*>(input_data), sizeof(input_data) * 2});
  53. EXPECT_EQ(7U, reader->GetTableSizeForTesting());
  54. EXPECT_FALSE(reader->FindEntryForAddress(0x01));
  55. EXPECT_FALSE(reader->FindEntryForAddress(0x100));
  56. EXPECT_FALSE(reader->FindEntryForAddress(0x1502));
  57. EXPECT_FALSE(reader->FindEntryForAddress(0x3000));
  58. EXPECT_FALSE(reader->FindEntryForAddress(0x2212));
  59. auto expect_frame = [&](ArmCFITable::FrameEntry expected, uintptr_t address) {
  60. auto result = reader->FindEntryForAddress(address);
  61. EXPECT_TRUE(result.has_value());
  62. EXPECT_EQ(expected, *result);
  63. };
  64. expect_frame({0x110, 0x4}, 0x1002);
  65. expect_frame({0x110, 0x4}, 0x1003);
  66. expect_frame({0x220, 0x4}, 0x1008);
  67. expect_frame({0x220, 0x4}, 0x1009);
  68. expect_frame({0x220, 0x4}, 0x1039);
  69. expect_frame({0x220, 0x8}, 0x1080);
  70. expect_frame({0x220, 0x8}, 0x1100);
  71. expect_frame({0x0, 0x0}, 0x2024);
  72. expect_frame({0x30, 0xc}, 0x2050);
  73. expect_frame({0x2c, 0x8}, 0x2208);
  74. expect_frame({0x2c, 0x8}, 0x2210);
  75. }
  76. TEST(ArmCFITableTest, InvalidTable) {
  77. auto parse_cfi_and_find =
  78. [](std::vector<uint16_t> data,
  79. uintptr_t address) -> absl::optional<ArmCFITable::FrameEntry> {
  80. auto reader = ArmCFITable::Parse(
  81. {reinterpret_cast<const uint8_t*>(data.data()), data.size() * 2});
  82. if (!reader)
  83. return absl::nullopt;
  84. return reader->FindEntryForAddress(address);
  85. };
  86. // No data.
  87. EXPECT_FALSE(parse_cfi_and_find({}, 0x0));
  88. // Empty UNW_INDEX.
  89. EXPECT_FALSE(parse_cfi_and_find({0x00, 0x00}, 0x0));
  90. // Missing UNW_INDEX data.
  91. EXPECT_FALSE(parse_cfi_and_find({0x01, 0x00}, 0x0));
  92. // No unwind info for address.
  93. EXPECT_FALSE(parse_cfi_and_find({0x02, 0x00, 0x0, 0x0, 0xffff}, 0x0));
  94. // entry_data_indices out of bound.
  95. EXPECT_FALSE(parse_cfi_and_find(
  96. {
  97. // UNW_INDEX size
  98. 0x01,
  99. 0x0,
  100. // UNW_INDEX
  101. 0x1000,
  102. 0x0,
  103. 0x0,
  104. // UNW_DATA
  105. 0x5,
  106. },
  107. 0x1000));
  108. EXPECT_FALSE(parse_cfi_and_find(
  109. {
  110. // UNW_INDEX size
  111. 0x01,
  112. 0x0,
  113. // UNW_INDEX
  114. 0x1000,
  115. 0x0,
  116. 0x0,
  117. },
  118. 0x1000));
  119. // Missing CFIDataRow.
  120. EXPECT_FALSE(parse_cfi_and_find(
  121. {
  122. // UNW_INDEX size
  123. 0x01,
  124. 0x0,
  125. // UNW_INDEX
  126. 0x1000,
  127. 0x0,
  128. 0x0,
  129. // UNW_DATA
  130. 0x5,
  131. 0x0,
  132. },
  133. 0x1000));
  134. // Invalid CFIDataRow.
  135. EXPECT_FALSE(parse_cfi_and_find(
  136. {
  137. // UNW_INDEX size
  138. 0x01,
  139. 0x0,
  140. // UNW_INDEX
  141. 0x1000,
  142. 0x0,
  143. 0x0,
  144. // UNW_DATA
  145. 0x1,
  146. 0x2,
  147. 0x0,
  148. },
  149. 0x1002));
  150. }
  151. } // namespace base