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