1 // Copyright 2021 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_DEBUG_BUFFERED_DWARF_READER_H_ 6 #define BASE_DEBUG_BUFFERED_DWARF_READER_H_ 7 8 #include <cstddef> 9 #include <cstdint> 10 11 #ifdef USE_SYMBOLIZE 12 13 namespace base { 14 namespace debug { 15 16 class BufferedDwarfReader { 17 public: 18 // Constructs a BufferedDwarfReader for a given `fd` starting 19 // `position` bytes from the start of the file. 20 // 21 // BufferedDwarfReader does not affect the `fd` state so it is completely 22 // okay to have multiple BufferedDwarfReader attached to one `fd` to act 23 // as cursors into different parts of the file. 24 BufferedDwarfReader(int fd, uint64_t position); 25 26 // Gets and Sets the absolute position from the start of the file. position()27 uint64_t position() const { return last_chunk_start_ + cursor_in_buffer_; } 28 set_position(uint64_t position)29 void set_position(uint64_t position) { 30 last_chunk_start_ = next_chunk_start_ = position; 31 32 // Invalidate buffer. 33 cursor_in_buffer_ = 0; 34 unconsumed_amount_ = 0; 35 } 36 ReadChar(char & value)37 bool ReadChar(char& value) { return ReadInt(value); } ReadInt8(uint8_t & value)38 bool ReadInt8(uint8_t& value) { return ReadInt(value); } ReadInt8(int8_t & value)39 bool ReadInt8(int8_t& value) { return ReadInt(value); } ReadInt16(uint16_t & value)40 bool ReadInt16(uint16_t& value) { return ReadInt(value); } ReadInt32(uint32_t & value)41 bool ReadInt32(uint32_t& value) { return ReadInt(value); } ReadInt64(uint64_t & value)42 bool ReadInt64(uint64_t& value) { return ReadInt(value); } 43 44 // Helper to read a null-terminated sequence of bytes. 45 // 46 // Reads at most `max_position - position()` bytes. 47 // 48 // Returns the number of bytes written into `out`. 49 // On a read error, the internal position of the BufferedDwarfReader may 50 // still be advanced. This should only happen if something funky 51 // happens at the OS layer at which case it's all best-effort 52 // recovery afterwards anyways. 53 size_t ReadCString(uint64_t max_position, char* out, size_t out_size); 54 55 // Leb128 is a variable-length integer encoding format. This reads 56 // both the signed and unsigned variants of this field. 57 bool ReadLeb128(uint64_t& value); 58 bool ReadLeb128(int64_t& value); 59 60 // Headers in DWARF often start with a length field of type "initial length." 61 // This is a variable-length field that both indicates if the entry is in 62 // 32-bit or 64-bit DWARF format and the length of the entry. 63 // 64 // Note: is_64bit refers to the DWARF format, not the target architecture. 65 // Most 64-bit binaries use 32-bit DWARF so is_64bit is frequently false. 66 bool ReadInitialLength(bool& is_64bit, uint64_t& length); 67 68 // Offsets inside DWARF are encoded at different sizes based on if it is 69 // 32-bit DWARF or 64-bit DWARF. The value of `is_64bit` is usually retrieved 70 // by a prior ReadInitialLength() call. 71 bool ReadOffset(bool is_64bit, uint64_t& offset); 72 73 // Addresses in DWARF are stored based on address size of the 74 // target architecture. This helper reads the correct sized field 75 // but then up-converts to a uint64_t type. It does an unsigned 76 // extension so 0xffffffff on a 32-bit system will still read out 77 // as 0xffffffff. 78 bool ReadAddress(uint8_t address_size, uint64_t& address); 79 80 // Many DWARF headers seem to start with 81 // length (initial length) 82 // version (ushort) 83 // offset (32bit or 64-bit dependent on initial length parsing) 84 // address_size (ubyte) 85 // 86 // The initial length also encodes if this is 32-bit or 64-bit dwarf. 87 // This function parses the above sequence of fields. 88 // 89 // It also returns `end_position` which is the first position after `length`. 90 bool ReadCommonHeader(bool& is_64bit, 91 uint64_t& length, 92 uint16_t& version, 93 uint64_t& offset, 94 uint8_t& address_size, 95 uint64_t& end_position); 96 97 private: 98 // Generic helper to read an integral value. The size read is determined by 99 // the width of `value` 100 template <typename IntType> ReadInt(IntType & value)101 bool ReadInt(IntType& value) { 102 return BufferedRead(&value, sizeof(value)); 103 } 104 105 bool BufferedRead(void* buf, const size_t count); 106 107 // The buffer and counters. In local testing, buffer sizes larger than 4096 108 // bytes provides negligible benefit, while buffer sizes less than 4096 bytes 109 // incur a significant performance penalty: compared to the original buffer 110 // size of 256 bytes, 4096 bytes is 2x faster. 111 char buf_[4096]; 112 size_t unconsumed_amount_ = 0; 113 size_t cursor_in_buffer_ = 0; 114 115 // The file descriptor for the file being read. 116 const int fd_; 117 118 // The position of the next chunk to read. 119 uint64_t next_chunk_start_; 120 121 // The position of the last chunk read. 122 uint64_t last_chunk_start_; 123 }; 124 125 } // namespace debug 126 } // namespace base 127 128 #endif 129 130 #endif // BASE_DEBUG_BUFFERED_DWARF_READER_H_ 131