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