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 #include "buffer.h" 27 28 namespace nogrod { 29 30 using berberis::bit_cast; 31 32 // The class provides assess to .debug_str_offsets section of the elf-file 33 class StringOffsetTable { 34 public: StringOffsetTable()35 StringOffsetTable() : format_{DwarfFormat::k32Bit} {} StringOffsetTable(Buffer<uint8_t> buffer)36 explicit StringOffsetTable(Buffer<uint8_t> buffer) 37 : buffer_{std::move(buffer)}, format_{DetectDwarfFormat(buffer_.data(), buffer_.size())} {} 38 39 StringOffsetTable(const StringOffsetTable&) = delete; 40 StringOffsetTable& operator=(const StringOffsetTable&) = delete; 41 42 StringOffsetTable(StringOffsetTable&&) = default; 43 StringOffsetTable& operator=(StringOffsetTable&&) = default; 44 45 // According to DWARF5 spec (7.26) DW_AT_str_offsets_base attribute 46 // points to the first entry following the header which is 8 for 32bit 47 // format and 16 for 64bit. We do not enforce it here, since this might 48 // not always be the case. But we do check that the base offset is greater 49 // than or equals to header size. GetStringOffset(size_t offsets_base,size_t index)50 [[nodiscard]] uint64_t GetStringOffset(size_t offsets_base, size_t index) const { 51 constexpr const size_t k64BitHeaderSize = 16; 52 constexpr const size_t k32BitHeaderSize = 8; 53 54 switch (format_) { 55 case DwarfFormat::k64Bit: 56 CHECK_GE(offsets_base, k64BitHeaderSize); 57 return GetOffsetAt<uint64_t>(offsets_base, index); 58 case DwarfFormat::k32Bit: 59 CHECK_GE(offsets_base, k32BitHeaderSize); 60 return GetOffsetAt<uint32_t>(offsets_base, index); 61 } 62 UNREACHABLE(); 63 } 64 65 private: DetectDwarfFormat(const uint8_t * table,size_t size)66 static DwarfFormat DetectDwarfFormat(const uint8_t* table, size_t size) { 67 CHECK_GE(size, sizeof(uint32_t)); 68 uint32_t size32 = *bit_cast<const uint32_t*>(table); 69 if (size32 == uint32_t{0xFFFF'FFFFu}) { 70 return DwarfFormat::k64Bit; 71 } else { 72 return DwarfFormat::k32Bit; 73 } 74 } 75 76 template <typename T> 77 [[nodiscard]] T GetOffsetAt(size_t offsets_base, size_t index) const { 78 CHECK_EQ(offsets_base % sizeof(T), 0); 79 uint64_t offset = offsets_base + index * sizeof(T); 80 CHECK_LE(offset + sizeof(T), buffer_.size()); 81 return *bit_cast<const T*>(buffer_.data() + offset); 82 } 83 84 Buffer<uint8_t> buffer_; 85 DwarfFormat format_; 86 }; 87 88 } // namespace nogrod 89 #endif // NOGROD_STRING_OFFSET_TABLE_H_ 90