blob: 1358e51dea64698f6068c578a06e1d61115596b6 [file] [log] [blame]
Christopher Ferris61d40972017-06-12 19:14:20 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Christopher Ferris61d40972017-06-12 19:14:20 -070017#include <stdint.h>
18
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -080019#include <unwindstack/DwarfError.h>
Christopher Ferrisd226a512017-07-14 10:37:19 -070020#include <unwindstack/DwarfStructs.h>
21#include <unwindstack/Memory.h>
22
Christopher Ferris94167032017-06-28 18:56:52 -070023#include "Check.h"
Christopher Ferrisc9dee842017-11-03 14:50:27 -070024#include "DwarfEhFrameWithHdr.h"
Christopher Ferris4cc36d22018-06-06 14:47:31 -070025#include "DwarfEncoding.h"
Christopher Ferrisd226a512017-07-14 10:37:19 -070026
27namespace unwindstack {
Christopher Ferris61d40972017-06-12 19:14:20 -070028
Christopher Ferris4cc36d22018-06-06 14:47:31 -070029static inline bool IsEncodingRelative(uint8_t encoding) {
30 encoding >>= 4;
31 return encoding > 0 && encoding <= DW_EH_PE_funcrel;
32}
33
Christopher Ferris61d40972017-06-12 19:14:20 -070034template <typename AddressType>
Christopher Ferris4ca98e12019-10-29 10:21:11 -070035bool DwarfEhFrameWithHdr<AddressType>::EhFrameInit(uint64_t offset, uint64_t size,
36 int64_t section_bias) {
37 return DwarfSectionImpl<AddressType>::Init(offset, size, section_bias);
38}
Christopher Ferris61d40972017-06-12 19:14:20 -070039
Christopher Ferris4ca98e12019-10-29 10:21:11 -070040template <typename AddressType>
41bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t, int64_t section_bias) {
Christopher Ferris61d40972017-06-12 19:14:20 -070042 memory_.clear_func_offset();
43 memory_.clear_text_offset();
44 memory_.set_data_offset(offset);
45 memory_.set_cur_offset(offset);
Christopher Ferris4ca98e12019-10-29 10:21:11 -070046
47 hdr_section_bias_ = section_bias;
Christopher Ferris61d40972017-06-12 19:14:20 -070048
49 // Read the first four bytes all at once.
Christopher Ferris4cc36d22018-06-06 14:47:31 -070050 uint8_t data[4];
Christopher Ferris61d40972017-06-12 19:14:20 -070051 if (!memory_.ReadBytes(data, 4)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -080052 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
53 last_error_.address = memory_.cur_offset();
Christopher Ferris61d40972017-06-12 19:14:20 -070054 return false;
55 }
56
57 version_ = data[0];
58 if (version_ != 1) {
59 // Unknown version.
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -080060 last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION;
Christopher Ferris61d40972017-06-12 19:14:20 -070061 return false;
62 }
63
Christopher Ferris4ca98e12019-10-29 10:21:11 -070064 uint8_t ptr_encoding = data[1];
Christopher Ferris61d40972017-06-12 19:14:20 -070065 uint8_t fde_count_encoding = data[2];
66 table_encoding_ = data[3];
67 table_entry_size_ = memory_.template GetEncodedSize<AddressType>(table_encoding_);
68
Christopher Ferris22d8e8e2019-03-29 12:34:58 -070069 // If we can't perform a binary search on the entries, it's not worth
70 // using this object. The calling code will fall back to the DwarfEhFrame
71 // object in this case.
72 if (table_entry_size_ == 0) {
73 last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
74 return false;
75 }
76
Christopher Ferris61d40972017-06-12 19:14:20 -070077 memory_.set_pc_offset(memory_.cur_offset());
Christopher Ferris4ca98e12019-10-29 10:21:11 -070078 uint64_t ptr_offset;
79 if (!memory_.template ReadEncodedValue<AddressType>(ptr_encoding, &ptr_offset)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -080080 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
81 last_error_.address = memory_.cur_offset();
Christopher Ferris61d40972017-06-12 19:14:20 -070082 return false;
83 }
84
85 memory_.set_pc_offset(memory_.cur_offset());
86 if (!memory_.template ReadEncodedValue<AddressType>(fde_count_encoding, &fde_count_)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -080087 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
88 last_error_.address = memory_.cur_offset();
Christopher Ferris61d40972017-06-12 19:14:20 -070089 return false;
90 }
91
Christopher Ferris1a141a02018-01-24 08:52:47 -080092 if (fde_count_ == 0) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -080093 last_error_.code = DWARF_ERROR_NO_FDES;
Christopher Ferris1a141a02018-01-24 08:52:47 -080094 return false;
95 }
96
Christopher Ferris4ca98e12019-10-29 10:21:11 -070097 hdr_entries_offset_ = memory_.cur_offset();
98 hdr_entries_data_offset_ = offset;
Christopher Ferris61d40972017-06-12 19:14:20 -070099
100 return true;
101}
102
103template <typename AddressType>
Christopher Ferris92acaac2018-06-21 10:44:02 -0700104const DwarfFde* DwarfEhFrameWithHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
105 uint64_t fde_offset;
106 if (!GetFdeOffsetFromPc(pc, &fde_offset)) {
Christopher Ferris61d40972017-06-12 19:14:20 -0700107 return nullptr;
108 }
Christopher Ferris92acaac2018-06-21 10:44:02 -0700109 const DwarfFde* fde = this->GetFdeFromOffset(fde_offset);
110 if (fde == nullptr) {
111 return nullptr;
112 }
113
Christopher Ferris4ca98e12019-10-29 10:21:11 -0700114 // There is a possibility that this entry points to a zero length FDE
115 // due to a bug. If this happens, try and find the non-zero length FDE
116 // from eh_frame directly. See b/142483624.
117 if (fde->pc_start == fde->pc_end) {
118 fde = DwarfSectionImpl<AddressType>::GetFdeFromPc(pc);
119 if (fde == nullptr) {
120 return nullptr;
121 }
122 }
123
Christopher Ferris92acaac2018-06-21 10:44:02 -0700124 // Guaranteed pc >= pc_start, need to check pc in the fde range.
125 if (pc < fde->pc_end) {
126 return fde;
127 }
128 last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
129 return nullptr;
Christopher Ferris61d40972017-06-12 19:14:20 -0700130}
131
132template <typename AddressType>
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700133const typename DwarfEhFrameWithHdr<AddressType>::FdeInfo*
134DwarfEhFrameWithHdr<AddressType>::GetFdeInfoFromIndex(size_t index) {
Christopher Ferris61d40972017-06-12 19:14:20 -0700135 auto entry = fde_info_.find(index);
136 if (entry != fde_info_.end()) {
137 return &fde_info_[index];
138 }
139 FdeInfo* info = &fde_info_[index];
140
Christopher Ferris4ca98e12019-10-29 10:21:11 -0700141 memory_.set_data_offset(hdr_entries_data_offset_);
142 memory_.set_cur_offset(hdr_entries_offset_ + 2 * index * table_entry_size_);
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700143 memory_.set_pc_offset(0);
Christopher Ferris61d40972017-06-12 19:14:20 -0700144 uint64_t value;
145 if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value) ||
146 !memory_.template ReadEncodedValue<AddressType>(table_encoding_, &info->offset)) {
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800147 last_error_.code = DWARF_ERROR_MEMORY_INVALID;
148 last_error_.address = memory_.cur_offset();
Christopher Ferris61d40972017-06-12 19:14:20 -0700149 fde_info_.erase(index);
150 return nullptr;
151 }
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700152
153 // Relative encodings require adding in the load bias.
154 if (IsEncodingRelative(table_encoding_)) {
Christopher Ferris4ca98e12019-10-29 10:21:11 -0700155 value += hdr_section_bias_;
Christopher Ferris4cc36d22018-06-06 14:47:31 -0700156 }
Christopher Ferrise37e2d02018-02-09 15:57:39 -0800157 info->pc = value;
Christopher Ferris61d40972017-06-12 19:14:20 -0700158 return info;
159}
160
161template <typename AddressType>
Christopher Ferris22d8e8e2019-03-29 12:34:58 -0700162bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) {
163 if (fde_count_ == 0) {
164 return false;
165 }
Christopher Ferris61d40972017-06-12 19:14:20 -0700166
167 size_t first = 0;
Christopher Ferris22d8e8e2019-03-29 12:34:58 -0700168 size_t last = fde_count_;
Christopher Ferris61d40972017-06-12 19:14:20 -0700169 while (first < last) {
170 size_t current = (first + last) / 2;
171 const FdeInfo* info = GetFdeInfoFromIndex(current);
Christopher Ferrisd96cbae2017-11-08 11:01:18 -0800172 if (info == nullptr) {
173 return false;
174 }
Christopher Ferris61d40972017-06-12 19:14:20 -0700175 if (pc == info->pc) {
176 *fde_offset = info->offset;
177 return true;
178 }
179 if (pc < info->pc) {
180 last = current;
181 } else {
182 first = current + 1;
183 }
184 }
185 if (last != 0) {
186 const FdeInfo* info = GetFdeInfoFromIndex(last - 1);
Christopher Ferrisd96cbae2017-11-08 11:01:18 -0800187 if (info == nullptr) {
188 return false;
189 }
Christopher Ferris61d40972017-06-12 19:14:20 -0700190 *fde_offset = info->offset;
191 return true;
192 }
193 return false;
194}
195
196template <typename AddressType>
Christopher Ferris92acaac2018-06-21 10:44:02 -0700197void DwarfEhFrameWithHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
198 for (size_t i = 0; i < fde_count_; i++) {
199 const FdeInfo* info = GetFdeInfoFromIndex(i);
200 if (info == nullptr) {
201 break;
202 }
203 const DwarfFde* fde = this->GetFdeFromOffset(info->offset);
204 if (fde == nullptr) {
205 break;
206 }
Christopher Ferris4ca98e12019-10-29 10:21:11 -0700207
208 // There is a possibility that this entry points to a zero length FDE
209 // due to a bug. If this happens, try and find the non-zero length FDE
210 // from eh_frame directly. See b/142483624.
211 if (fde->pc_start == fde->pc_end) {
212 const DwarfFde* fde_real = DwarfSectionImpl<AddressType>::GetFdeFromPc(fde->pc_start);
213 if (fde_real != nullptr) {
214 fde = fde_real;
215 }
216 }
Christopher Ferris92acaac2018-06-21 10:44:02 -0700217 fdes->push_back(fde);
218 }
219}
220
Christopher Ferrisc9dee842017-11-03 14:50:27 -0700221// Explicitly instantiate DwarfEhFrameWithHdr
222template class DwarfEhFrameWithHdr<uint32_t>;
223template class DwarfEhFrameWithHdr<uint64_t>;
Christopher Ferrisd226a512017-07-14 10:37:19 -0700224
225} // namespace unwindstack