• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef NOGROD_STRING_OFFSET_TABLE_H_
18 #define NOGROD_STRING_OFFSET_TABLE_H_
19 
20 #include <cstdint>
21 
22 #include "berberis/base/bit_util.h"
23 #include "berberis/base/checks.h"
24 #include "dwarf_constants.h"
25 
26 namespace nogrod {
27 
28 using berberis::bit_cast;
29 
30 // The class provides assess to .debug_str_offsets section of the elf-file
31 class StringOffsetTable {
32  public:
StringOffsetTable(const uint8_t * table,size_t size)33   explicit StringOffsetTable(const uint8_t* table, size_t size)
34       : table_{table}, size_{size}, format_{DetectDwarfFormat(table, size)} {}
35 
36   // According to DWARF5 spec (7.26) DW_AT_str_offsets_base attribute
37   // points to the first entry following the header which is 8 for 32bit
38   // format and 16 for 64bit. We do not enforce it here, since this might
39   // not always be the case. But we do check that the base offset is greater
40   // than or equals to header size.
GetStringOffset(size_t offsets_base,size_t index)41   [[nodiscard]] uint64_t GetStringOffset(size_t offsets_base, size_t index) const {
42     constexpr const size_t k64BitHeaderSize = 16;
43     constexpr const size_t k32BitHeaderSize = 8;
44 
45     switch (format_) {
46       case DwarfFormat::k64Bit:
47         CHECK_GE(offsets_base, k64BitHeaderSize);
48         return GetOffsetAt<uint64_t>(offsets_base, index);
49       case DwarfFormat::k32Bit:
50         CHECK_GE(offsets_base, k32BitHeaderSize);
51         return GetOffsetAt<uint32_t>(offsets_base, index);
52     }
53     UNREACHABLE();
54   }
55 
56  private:
DetectDwarfFormat(const uint8_t * table,size_t size)57   static DwarfFormat DetectDwarfFormat(const uint8_t* table, size_t size) {
58     CHECK_GE(size, sizeof(uint32_t));
59     uint32_t size32 = *bit_cast<const uint32_t*>(table);
60     if (size32 == uint32_t{0xFFFF'FFFFu}) {
61       return DwarfFormat::k64Bit;
62     } else {
63       return DwarfFormat::k32Bit;
64     }
65   }
66 
67   template <typename T>
68   [[nodiscard]] T GetOffsetAt(size_t offsets_base, size_t index) const {
69     CHECK_EQ(offsets_base % sizeof(T), 0);
70     uint64_t offset = offsets_base + index * sizeof(T);
71     CHECK_LE(offset + sizeof(T), size_);
72     return *bit_cast<const T*>(table_ + offset);
73   }
74 
75   const uint8_t* table_;
76   const size_t size_;
77   const DwarfFormat format_;
78 };
79 
80 }  // namespace nogrod
81 #endif  // NOGROD_STRING_OFFSET_TABLE_H_
82