123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- /*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include <stdint.h>
- #include <unwindstack/DwarfError.h>
- #include <unwindstack/DwarfStructs.h>
- #include <unwindstack/Memory.h>
- #include "Check.h"
- #include "DwarfEhFrameWithHdr.h"
- #include "DwarfEncoding.h"
- namespace unwindstack {
- static inline bool IsEncodingRelative(uint8_t encoding) {
- encoding >>= 4;
- return encoding > 0 && encoding <= DW_EH_PE_funcrel;
- }
- template <typename AddressType>
- bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size, uint64_t load_bias) {
- load_bias_ = load_bias;
- memory_.clear_func_offset();
- memory_.clear_text_offset();
- memory_.set_data_offset(offset);
- memory_.set_cur_offset(offset);
- pc_offset_ = offset;
- // Read the first four bytes all at once.
- uint8_t data[4];
- if (!memory_.ReadBytes(data, 4)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- version_ = data[0];
- if (version_ != 1) {
- // Unknown version.
- last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION;
- return false;
- }
- ptr_encoding_ = data[1];
- uint8_t fde_count_encoding = data[2];
- table_encoding_ = data[3];
- table_entry_size_ = memory_.template GetEncodedSize<AddressType>(table_encoding_);
- // If we can't perform a binary search on the entries, it's not worth
- // using this object. The calling code will fall back to the DwarfEhFrame
- // object in this case.
- if (table_entry_size_ == 0) {
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- memory_.set_pc_offset(memory_.cur_offset());
- if (!memory_.template ReadEncodedValue<AddressType>(ptr_encoding_, &ptr_offset_)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- memory_.set_pc_offset(memory_.cur_offset());
- if (!memory_.template ReadEncodedValue<AddressType>(fde_count_encoding, &fde_count_)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (fde_count_ == 0) {
- last_error_.code = DWARF_ERROR_NO_FDES;
- return false;
- }
- entries_offset_ = memory_.cur_offset();
- entries_end_ = offset + size;
- entries_data_offset_ = offset;
- cur_entries_offset_ = entries_offset_;
- return true;
- }
- template <typename AddressType>
- const DwarfFde* DwarfEhFrameWithHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
- uint64_t fde_offset;
- if (!GetFdeOffsetFromPc(pc, &fde_offset)) {
- return nullptr;
- }
- const DwarfFde* fde = this->GetFdeFromOffset(fde_offset);
- if (fde == nullptr) {
- return nullptr;
- }
- // Guaranteed pc >= pc_start, need to check pc in the fde range.
- if (pc < fde->pc_end) {
- return fde;
- }
- last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
- return nullptr;
- }
- template <typename AddressType>
- const typename DwarfEhFrameWithHdr<AddressType>::FdeInfo*
- DwarfEhFrameWithHdr<AddressType>::GetFdeInfoFromIndex(size_t index) {
- auto entry = fde_info_.find(index);
- if (entry != fde_info_.end()) {
- return &fde_info_[index];
- }
- FdeInfo* info = &fde_info_[index];
- memory_.set_data_offset(entries_data_offset_);
- memory_.set_cur_offset(entries_offset_ + 2 * index * table_entry_size_);
- memory_.set_pc_offset(0);
- uint64_t value;
- if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value) ||
- !memory_.template ReadEncodedValue<AddressType>(table_encoding_, &info->offset)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- fde_info_.erase(index);
- return nullptr;
- }
- // Relative encodings require adding in the load bias.
- if (IsEncodingRelative(table_encoding_)) {
- value += load_bias_;
- }
- info->pc = value;
- return info;
- }
- template <typename AddressType>
- bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) {
- if (fde_count_ == 0) {
- return false;
- }
- size_t first = 0;
- size_t last = fde_count_;
- while (first < last) {
- size_t current = (first + last) / 2;
- const FdeInfo* info = GetFdeInfoFromIndex(current);
- if (info == nullptr) {
- return false;
- }
- if (pc == info->pc) {
- *fde_offset = info->offset;
- return true;
- }
- if (pc < info->pc) {
- last = current;
- } else {
- first = current + 1;
- }
- }
- if (last != 0) {
- const FdeInfo* info = GetFdeInfoFromIndex(last - 1);
- if (info == nullptr) {
- return false;
- }
- *fde_offset = info->offset;
- return true;
- }
- return false;
- }
- template <typename AddressType>
- void DwarfEhFrameWithHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
- for (size_t i = 0; i < fde_count_; i++) {
- const FdeInfo* info = GetFdeInfoFromIndex(i);
- if (info == nullptr) {
- break;
- }
- const DwarfFde* fde = this->GetFdeFromOffset(info->offset);
- if (fde == nullptr) {
- break;
- }
- fdes->push_back(fde);
- }
- }
- // Explicitly instantiate DwarfEhFrameWithHdr
- template class DwarfEhFrameWithHdr<uint32_t>;
- template class DwarfEhFrameWithHdr<uint64_t>;
- } // namespace unwindstack
|