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