123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- // Copyright (c) 2021 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "base/debug/buffered_dwarf_reader.h"
- #ifdef USE_SYMBOLIZE
- #include <algorithm>
- #include <cstring>
- #include "base/numerics/safe_conversions.h"
- #include "base/third_party/symbolize/symbolize.h"
- namespace base::debug {
- BufferedDwarfReader::BufferedDwarfReader(int fd, uint64_t position)
- : fd_(fd), next_chunk_start_(position), last_chunk_start_(position) {}
- size_t BufferedDwarfReader::ReadCString(uint64_t max_position,
- char* out,
- size_t out_size) {
- char character;
- size_t bytes_written = 0;
- do {
- if (!ReadChar(character)) {
- return 0;
- }
- if (out && bytes_written < out_size) {
- out[bytes_written++] = character;
- }
- } while (character != '\0' && position() < max_position);
- if (out) {
- out[std::min(bytes_written, out_size - 1)] = '\0';
- }
- return bytes_written;
- }
- bool BufferedDwarfReader::ReadLeb128(uint64_t& value) {
- value = 0;
- uint8_t byte;
- int shift = 0;
- do {
- if (!ReadInt8(byte))
- return false;
- value |= static_cast<uint64_t>(byte & 0x7F) << shift;
- shift += 7;
- } while (byte & 0x80);
- return true;
- }
- bool BufferedDwarfReader::ReadLeb128(int64_t& value) {
- value = 0;
- uint8_t byte;
- int shift = 0;
- bool sign_bit = false;
- do {
- if (!ReadInt8(byte))
- return false;
- value |= static_cast<uint64_t>(byte & 0x7F) << shift;
- shift += 7;
- sign_bit = byte & 0x40;
- } while (byte & 0x80);
- constexpr int bits_in_output = sizeof(value) * 8;
- if ((shift < bits_in_output) && sign_bit) {
- value |= -(1 << shift);
- }
- return true;
- }
- bool BufferedDwarfReader::ReadInitialLength(bool& is_64bit, uint64_t& length) {
- uint32_t token_32bit;
- if (!ReadInt32(token_32bit)) {
- return false;
- }
- // Dwarf 3 introduced an extended length field that both indicates this is
- // DWARF-64 and changes how the size is encoded. 0xfffffff0 and higher are
- // reserved with 0xffffffff meaning it's the extended field with the
- // following 64-bits being the full length.
- if (token_32bit < 0xfffffff0) {
- length = token_32bit;
- is_64bit = false;
- return true;
- }
- if (token_32bit != 0xffffffff) {
- return false;
- }
- if (!ReadInt64(length)) {
- return false;
- }
- is_64bit = true;
- return true;
- }
- bool BufferedDwarfReader::ReadOffset(bool is_64bit, uint64_t& offset) {
- if (is_64bit) {
- if (!ReadInt64(offset)) {
- return false;
- }
- } else {
- uint32_t tmp;
- if (!ReadInt32(tmp)) {
- return false;
- }
- offset = tmp;
- }
- return true;
- }
- bool BufferedDwarfReader::ReadAddress(uint8_t address_size, uint64_t& address) {
- // Note `address_size` indicates the numbrer of bytes in the address.
- switch (address_size) {
- case 2: {
- uint16_t tmp;
- if (!ReadInt16(tmp))
- return false;
- address = tmp;
- } break;
- case 4: {
- uint32_t tmp;
- if (!ReadInt32(tmp))
- return false;
- address = tmp;
- } break;
- case 8: {
- uint64_t tmp;
- if (!ReadInt64(tmp))
- return false;
- address = tmp;
- } break;
- default:
- return false;
- }
- return true;
- }
- bool BufferedDwarfReader::ReadCommonHeader(bool& is_64bit,
- uint64_t& length,
- uint16_t& version,
- uint64_t& offset,
- uint8_t& address_size,
- uint64_t& end_position) {
- if (!ReadInitialLength(is_64bit, length)) {
- return false;
- }
- end_position = position() + length;
- if (!ReadInt16(version)) {
- return false;
- }
- if (!ReadOffset(is_64bit, offset)) {
- return false;
- }
- if (!ReadInt8(address_size)) {
- return false;
- }
- return true;
- }
- bool BufferedDwarfReader::BufferedRead(void* out, const size_t bytes) {
- size_t bytes_left = bytes;
- while (bytes_left > 0) {
- // Refresh the buffer.
- if (unconsumed_amount_ == 0) {
- if (!base::IsValueInRangeForNumericType<off_t>(next_chunk_start_))
- return false;
- const ssize_t unconsumed_amount = google::ReadFromOffset(
- fd_, buf_, sizeof(buf_), static_cast<off_t>(next_chunk_start_));
- if (unconsumed_amount_ <= 0) {
- // Read error.
- return false;
- }
- unconsumed_amount_ = static_cast<size_t>(unconsumed_amount);
- last_chunk_start_ = next_chunk_start_;
- next_chunk_start_ += unconsumed_amount_;
- cursor_in_buffer_ = 0;
- }
- size_t to_copy = std::min(bytes_left, unconsumed_amount_);
- memcpy(out, &buf_[cursor_in_buffer_], to_copy);
- unconsumed_amount_ -= to_copy;
- cursor_in_buffer_ += to_copy;
- bytes_left -= to_copy;
- }
- return true;
- }
- } // namespace base::debug
- #endif
|