xref: /aosp_15_r20/external/cronet/base/debug/buffered_dwarf_reader.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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