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