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