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