xref: /aosp_15_r20/external/cronet/base/debug/buffered_dwarf_reader.cc (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 #include "base/debug/buffered_dwarf_reader.h"
6 
7 #ifdef USE_SYMBOLIZE
8 
9 #include <algorithm>
10 #include <cstring>
11 
12 #include "base/numerics/safe_conversions.h"
13 #include "base/third_party/symbolize/symbolize.h"
14 
15 namespace base::debug {
16 
BufferedDwarfReader(int fd,uint64_t position)17 BufferedDwarfReader::BufferedDwarfReader(int fd, uint64_t position)
18     : fd_(fd), next_chunk_start_(position), last_chunk_start_(position) {}
19 
ReadCString(uint64_t max_position,char * out,size_t out_size)20 size_t BufferedDwarfReader::ReadCString(uint64_t max_position,
21                                         char* out,
22                                         size_t out_size) {
23   char character;
24   size_t bytes_written = 0;
25   do {
26     if (!ReadChar(character)) {
27       return 0;
28     }
29 
30     if (out && bytes_written < out_size) {
31       out[bytes_written++] = character;
32     }
33   } while (character != '\0' && position() < max_position);
34 
35   if (out) {
36     out[std::min(bytes_written, out_size - 1)] = '\0';
37   }
38 
39   return bytes_written;
40 }
41 
ReadLeb128(uint64_t & value)42 bool BufferedDwarfReader::ReadLeb128(uint64_t& value) {
43   value = 0;
44   uint8_t byte;
45   int shift = 0;
46   do {
47     if (!ReadInt8(byte))
48       return false;
49     value |= static_cast<uint64_t>(byte & 0x7F) << shift;
50     shift += 7;
51   } while (byte & 0x80);
52   return true;
53 }
54 
ReadLeb128(int64_t & value)55 bool BufferedDwarfReader::ReadLeb128(int64_t& value) {
56   value = 0;
57   uint8_t byte;
58   int shift = 0;
59   bool sign_bit = false;
60   do {
61     if (!ReadInt8(byte))
62       return false;
63     value |= static_cast<uint64_t>(byte & 0x7F) << shift;
64     shift += 7;
65     sign_bit = byte & 0x40;
66   } while (byte & 0x80);
67   constexpr int bits_in_output = sizeof(value) * 8;
68   if ((shift < bits_in_output) && sign_bit) {
69     value |= -(1 << shift);
70   }
71   return true;
72 }
73 
ReadInitialLength(bool & is_64bit,uint64_t & length)74 bool BufferedDwarfReader::ReadInitialLength(bool& is_64bit, uint64_t& length) {
75   uint32_t token_32bit;
76 
77   if (!ReadInt32(token_32bit)) {
78     return false;
79   }
80 
81   // Dwarf 3 introduced an extended length field that both indicates this is
82   // DWARF-64 and changes how the size is encoded. 0xfffffff0 and higher are
83   // reserved with 0xffffffff meaning it's the extended field with the
84   // following 64-bits being the full length.
85   if (token_32bit < 0xfffffff0) {
86     length = token_32bit;
87     is_64bit = false;
88     return true;
89   }
90 
91   if (token_32bit != 0xffffffff) {
92     return false;
93   }
94 
95   if (!ReadInt64(length)) {
96     return false;
97   }
98 
99   is_64bit = true;
100   return true;
101 }
102 
ReadOffset(bool is_64bit,uint64_t & offset)103 bool BufferedDwarfReader::ReadOffset(bool is_64bit, uint64_t& offset) {
104   if (is_64bit) {
105     if (!ReadInt64(offset)) {
106       return false;
107     }
108   } else {
109     uint32_t tmp;
110     if (!ReadInt32(tmp)) {
111       return false;
112     }
113     offset = tmp;
114   }
115   return true;
116 }
117 
ReadAddress(uint8_t address_size,uint64_t & address)118 bool BufferedDwarfReader::ReadAddress(uint8_t address_size, uint64_t& address) {
119   // Note `address_size` indicates the numbrer of bytes in the address.
120   switch (address_size) {
121     case 2: {
122       uint16_t tmp;
123       if (!ReadInt16(tmp))
124         return false;
125       address = tmp;
126     } break;
127 
128     case 4: {
129       uint32_t tmp;
130       if (!ReadInt32(tmp))
131         return false;
132       address = tmp;
133     } break;
134 
135     case 8: {
136       uint64_t tmp;
137       if (!ReadInt64(tmp))
138         return false;
139       address = tmp;
140     } break;
141 
142     default:
143       return false;
144   }
145   return true;
146 }
147 
ReadCommonHeader(bool & is_64bit,uint64_t & length,uint16_t & version,uint64_t & offset,uint8_t & address_size,uint64_t & end_position)148 bool BufferedDwarfReader::ReadCommonHeader(bool& is_64bit,
149                                            uint64_t& length,
150                                            uint16_t& version,
151                                            uint64_t& offset,
152                                            uint8_t& address_size,
153                                            uint64_t& end_position) {
154   if (!ReadInitialLength(is_64bit, length)) {
155     return false;
156   }
157   end_position = position() + length;
158 
159   if (!ReadInt16(version)) {
160     return false;
161   }
162 
163   if (!ReadOffset(is_64bit, offset)) {
164     return false;
165   }
166 
167   if (!ReadInt8(address_size)) {
168     return false;
169   }
170 
171   return true;
172 }
173 
BufferedRead(void * out,const size_t bytes)174 bool BufferedDwarfReader::BufferedRead(void* out, const size_t bytes) {
175   size_t bytes_left = bytes;
176   while (bytes_left > 0) {
177     // Refresh the buffer.
178     if (unconsumed_amount_ == 0) {
179       if (!base::IsValueInRangeForNumericType<size_t>(next_chunk_start_))
180         return false;
181       const ssize_t unconsumed_amount = google::ReadFromOffset(
182           fd_, buf_, sizeof(buf_), static_cast<size_t>(next_chunk_start_));
183       if (unconsumed_amount <= 0) {
184         // Read error.
185         return false;
186       }
187       unconsumed_amount_ = static_cast<size_t>(unconsumed_amount);
188 
189       last_chunk_start_ = next_chunk_start_;
190       next_chunk_start_ += unconsumed_amount_;
191       cursor_in_buffer_ = 0;
192     }
193 
194     size_t to_copy = std::min(bytes_left, unconsumed_amount_);
195     memcpy(out, &buf_[cursor_in_buffer_], to_copy);
196     unconsumed_amount_ -= to_copy;
197     cursor_in_buffer_ += to_copy;
198     bytes_left -= to_copy;
199   }
200   return true;
201 }
202 
203 }  // namespace base::debug
204 
205 #endif
206