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