1*eb293b8fSAndroid Build Coastguard Worker /*
2*eb293b8fSAndroid Build Coastguard Worker * Copyright (C) 2017 The Android Open Source Project
3*eb293b8fSAndroid Build Coastguard Worker *
4*eb293b8fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*eb293b8fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*eb293b8fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*eb293b8fSAndroid Build Coastguard Worker *
8*eb293b8fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*eb293b8fSAndroid Build Coastguard Worker *
10*eb293b8fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*eb293b8fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*eb293b8fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*eb293b8fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*eb293b8fSAndroid Build Coastguard Worker * limitations under the License.
15*eb293b8fSAndroid Build Coastguard Worker */
16*eb293b8fSAndroid Build Coastguard Worker
17*eb293b8fSAndroid Build Coastguard Worker #include <stdint.h>
18*eb293b8fSAndroid Build Coastguard Worker
19*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/DwarfError.h>
20*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/DwarfStructs.h>
21*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/Elf.h>
22*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/ElfInterface.h>
23*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/Memory.h>
24*eb293b8fSAndroid Build Coastguard Worker
25*eb293b8fSAndroid Build Coastguard Worker #include "Check.h"
26*eb293b8fSAndroid Build Coastguard Worker #include "DwarfEhFrameWithHdr.h"
27*eb293b8fSAndroid Build Coastguard Worker #include "DwarfEncoding.h"
28*eb293b8fSAndroid Build Coastguard Worker
29*eb293b8fSAndroid Build Coastguard Worker namespace unwindstack {
30*eb293b8fSAndroid Build Coastguard Worker
IsEncodingRelative(uint8_t encoding)31*eb293b8fSAndroid Build Coastguard Worker static inline bool IsEncodingRelative(uint8_t encoding) {
32*eb293b8fSAndroid Build Coastguard Worker encoding >>= 4;
33*eb293b8fSAndroid Build Coastguard Worker return encoding > 0 && encoding <= DW_EH_PE_funcrel;
34*eb293b8fSAndroid Build Coastguard Worker }
35*eb293b8fSAndroid Build Coastguard Worker
36*eb293b8fSAndroid Build Coastguard Worker template <typename AddressType>
EhFrameInit(const SectionInfo & info)37*eb293b8fSAndroid Build Coastguard Worker bool DwarfEhFrameWithHdr<AddressType>::EhFrameInit(const SectionInfo& info) {
38*eb293b8fSAndroid Build Coastguard Worker return DwarfSectionImpl<AddressType>::Init(info);
39*eb293b8fSAndroid Build Coastguard Worker }
40*eb293b8fSAndroid Build Coastguard Worker
41*eb293b8fSAndroid Build Coastguard Worker template <typename AddressType>
Init(const SectionInfo & info)42*eb293b8fSAndroid Build Coastguard Worker bool DwarfEhFrameWithHdr<AddressType>::Init(const SectionInfo& info) {
43*eb293b8fSAndroid Build Coastguard Worker if (info.flags & SHF_COMPRESSED) {
44*eb293b8fSAndroid Build Coastguard Worker return false;
45*eb293b8fSAndroid Build Coastguard Worker }
46*eb293b8fSAndroid Build Coastguard Worker
47*eb293b8fSAndroid Build Coastguard Worker memory_.clear_func_offset();
48*eb293b8fSAndroid Build Coastguard Worker memory_.clear_text_offset();
49*eb293b8fSAndroid Build Coastguard Worker memory_.set_data_offset(info.offset);
50*eb293b8fSAndroid Build Coastguard Worker memory_.set_cur_offset(info.offset);
51*eb293b8fSAndroid Build Coastguard Worker
52*eb293b8fSAndroid Build Coastguard Worker hdr_section_bias_ = info.bias;
53*eb293b8fSAndroid Build Coastguard Worker
54*eb293b8fSAndroid Build Coastguard Worker // Read the first four bytes all at once.
55*eb293b8fSAndroid Build Coastguard Worker uint8_t data[4];
56*eb293b8fSAndroid Build Coastguard Worker if (!memory_.ReadBytes(data, 4)) {
57*eb293b8fSAndroid Build Coastguard Worker last_error_.code = DWARF_ERROR_MEMORY_INVALID;
58*eb293b8fSAndroid Build Coastguard Worker last_error_.address = memory_.cur_offset();
59*eb293b8fSAndroid Build Coastguard Worker return false;
60*eb293b8fSAndroid Build Coastguard Worker }
61*eb293b8fSAndroid Build Coastguard Worker
62*eb293b8fSAndroid Build Coastguard Worker version_ = data[0];
63*eb293b8fSAndroid Build Coastguard Worker if (version_ != 1) {
64*eb293b8fSAndroid Build Coastguard Worker // Unknown version.
65*eb293b8fSAndroid Build Coastguard Worker last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION;
66*eb293b8fSAndroid Build Coastguard Worker return false;
67*eb293b8fSAndroid Build Coastguard Worker }
68*eb293b8fSAndroid Build Coastguard Worker
69*eb293b8fSAndroid Build Coastguard Worker uint8_t ptr_encoding = data[1];
70*eb293b8fSAndroid Build Coastguard Worker uint8_t fde_count_encoding = data[2];
71*eb293b8fSAndroid Build Coastguard Worker table_encoding_ = data[3];
72*eb293b8fSAndroid Build Coastguard Worker table_entry_size_ = memory_.template GetEncodedSize<AddressType>(table_encoding_);
73*eb293b8fSAndroid Build Coastguard Worker
74*eb293b8fSAndroid Build Coastguard Worker // If we can't perform a binary search on the entries, it's not worth
75*eb293b8fSAndroid Build Coastguard Worker // using this object. The calling code will fall back to the DwarfEhFrame
76*eb293b8fSAndroid Build Coastguard Worker // object in this case.
77*eb293b8fSAndroid Build Coastguard Worker if (table_entry_size_ == 0) {
78*eb293b8fSAndroid Build Coastguard Worker last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
79*eb293b8fSAndroid Build Coastguard Worker return false;
80*eb293b8fSAndroid Build Coastguard Worker }
81*eb293b8fSAndroid Build Coastguard Worker
82*eb293b8fSAndroid Build Coastguard Worker memory_.set_pc_offset(memory_.cur_offset());
83*eb293b8fSAndroid Build Coastguard Worker uint64_t ptr_offset;
84*eb293b8fSAndroid Build Coastguard Worker if (!memory_.template ReadEncodedValue<AddressType>(ptr_encoding, &ptr_offset)) {
85*eb293b8fSAndroid Build Coastguard Worker last_error_.code = DWARF_ERROR_MEMORY_INVALID;
86*eb293b8fSAndroid Build Coastguard Worker last_error_.address = memory_.cur_offset();
87*eb293b8fSAndroid Build Coastguard Worker return false;
88*eb293b8fSAndroid Build Coastguard Worker }
89*eb293b8fSAndroid Build Coastguard Worker
90*eb293b8fSAndroid Build Coastguard Worker memory_.set_pc_offset(memory_.cur_offset());
91*eb293b8fSAndroid Build Coastguard Worker if (!memory_.template ReadEncodedValue<AddressType>(fde_count_encoding, &fde_count_)) {
92*eb293b8fSAndroid Build Coastguard Worker last_error_.code = DWARF_ERROR_MEMORY_INVALID;
93*eb293b8fSAndroid Build Coastguard Worker last_error_.address = memory_.cur_offset();
94*eb293b8fSAndroid Build Coastguard Worker return false;
95*eb293b8fSAndroid Build Coastguard Worker }
96*eb293b8fSAndroid Build Coastguard Worker
97*eb293b8fSAndroid Build Coastguard Worker if (fde_count_ == 0) {
98*eb293b8fSAndroid Build Coastguard Worker last_error_.code = DWARF_ERROR_NO_FDES;
99*eb293b8fSAndroid Build Coastguard Worker return false;
100*eb293b8fSAndroid Build Coastguard Worker }
101*eb293b8fSAndroid Build Coastguard Worker
102*eb293b8fSAndroid Build Coastguard Worker hdr_entries_offset_ = memory_.cur_offset();
103*eb293b8fSAndroid Build Coastguard Worker hdr_entries_data_offset_ = info.offset;
104*eb293b8fSAndroid Build Coastguard Worker
105*eb293b8fSAndroid Build Coastguard Worker return true;
106*eb293b8fSAndroid Build Coastguard Worker }
107*eb293b8fSAndroid Build Coastguard Worker
108*eb293b8fSAndroid Build Coastguard Worker template <typename AddressType>
GetFdeFromPc(uint64_t pc)109*eb293b8fSAndroid Build Coastguard Worker const DwarfFde* DwarfEhFrameWithHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
110*eb293b8fSAndroid Build Coastguard Worker uint64_t fde_offset;
111*eb293b8fSAndroid Build Coastguard Worker if (!GetFdeOffsetFromPc(pc, &fde_offset)) {
112*eb293b8fSAndroid Build Coastguard Worker return nullptr;
113*eb293b8fSAndroid Build Coastguard Worker }
114*eb293b8fSAndroid Build Coastguard Worker const DwarfFde* fde = this->GetFdeFromOffset(fde_offset);
115*eb293b8fSAndroid Build Coastguard Worker if (fde == nullptr) {
116*eb293b8fSAndroid Build Coastguard Worker return nullptr;
117*eb293b8fSAndroid Build Coastguard Worker }
118*eb293b8fSAndroid Build Coastguard Worker
119*eb293b8fSAndroid Build Coastguard Worker // There is a possibility that this entry points to a zero length FDE
120*eb293b8fSAndroid Build Coastguard Worker // due to a bug. If this happens, try and find the non-zero length FDE
121*eb293b8fSAndroid Build Coastguard Worker // from eh_frame directly. See b/142483624.
122*eb293b8fSAndroid Build Coastguard Worker if (fde->pc_start == fde->pc_end) {
123*eb293b8fSAndroid Build Coastguard Worker fde = DwarfSectionImpl<AddressType>::GetFdeFromPc(pc);
124*eb293b8fSAndroid Build Coastguard Worker if (fde == nullptr) {
125*eb293b8fSAndroid Build Coastguard Worker return nullptr;
126*eb293b8fSAndroid Build Coastguard Worker }
127*eb293b8fSAndroid Build Coastguard Worker }
128*eb293b8fSAndroid Build Coastguard Worker
129*eb293b8fSAndroid Build Coastguard Worker // Guaranteed pc >= pc_start, need to check pc in the fde range.
130*eb293b8fSAndroid Build Coastguard Worker if (pc < fde->pc_end) {
131*eb293b8fSAndroid Build Coastguard Worker return fde;
132*eb293b8fSAndroid Build Coastguard Worker }
133*eb293b8fSAndroid Build Coastguard Worker last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
134*eb293b8fSAndroid Build Coastguard Worker return nullptr;
135*eb293b8fSAndroid Build Coastguard Worker }
136*eb293b8fSAndroid Build Coastguard Worker
137*eb293b8fSAndroid Build Coastguard Worker template <typename AddressType>
138*eb293b8fSAndroid Build Coastguard Worker const typename DwarfEhFrameWithHdr<AddressType>::FdeInfo*
GetFdeInfoFromIndex(size_t index)139*eb293b8fSAndroid Build Coastguard Worker DwarfEhFrameWithHdr<AddressType>::GetFdeInfoFromIndex(size_t index) {
140*eb293b8fSAndroid Build Coastguard Worker auto entry = fde_info_.find(index);
141*eb293b8fSAndroid Build Coastguard Worker if (entry != fde_info_.end()) {
142*eb293b8fSAndroid Build Coastguard Worker return &entry->second;
143*eb293b8fSAndroid Build Coastguard Worker }
144*eb293b8fSAndroid Build Coastguard Worker FdeInfo* info = &fde_info_[index];
145*eb293b8fSAndroid Build Coastguard Worker
146*eb293b8fSAndroid Build Coastguard Worker memory_.set_data_offset(hdr_entries_data_offset_);
147*eb293b8fSAndroid Build Coastguard Worker memory_.set_cur_offset(hdr_entries_offset_ + 2 * index * table_entry_size_);
148*eb293b8fSAndroid Build Coastguard Worker memory_.set_pc_offset(0);
149*eb293b8fSAndroid Build Coastguard Worker uint64_t value;
150*eb293b8fSAndroid Build Coastguard Worker if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value) ||
151*eb293b8fSAndroid Build Coastguard Worker !memory_.template ReadEncodedValue<AddressType>(table_encoding_, &info->offset)) {
152*eb293b8fSAndroid Build Coastguard Worker last_error_.code = DWARF_ERROR_MEMORY_INVALID;
153*eb293b8fSAndroid Build Coastguard Worker last_error_.address = memory_.cur_offset();
154*eb293b8fSAndroid Build Coastguard Worker fde_info_.erase(index);
155*eb293b8fSAndroid Build Coastguard Worker return nullptr;
156*eb293b8fSAndroid Build Coastguard Worker }
157*eb293b8fSAndroid Build Coastguard Worker
158*eb293b8fSAndroid Build Coastguard Worker // Relative encodings require adding in the load bias.
159*eb293b8fSAndroid Build Coastguard Worker if (IsEncodingRelative(table_encoding_)) {
160*eb293b8fSAndroid Build Coastguard Worker value += hdr_section_bias_;
161*eb293b8fSAndroid Build Coastguard Worker }
162*eb293b8fSAndroid Build Coastguard Worker info->pc = value;
163*eb293b8fSAndroid Build Coastguard Worker return info;
164*eb293b8fSAndroid Build Coastguard Worker }
165*eb293b8fSAndroid Build Coastguard Worker
166*eb293b8fSAndroid Build Coastguard Worker template <typename AddressType>
GetFdeOffsetFromPc(uint64_t pc,uint64_t * fde_offset)167*eb293b8fSAndroid Build Coastguard Worker bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) {
168*eb293b8fSAndroid Build Coastguard Worker if (fde_count_ == 0) {
169*eb293b8fSAndroid Build Coastguard Worker return false;
170*eb293b8fSAndroid Build Coastguard Worker }
171*eb293b8fSAndroid Build Coastguard Worker
172*eb293b8fSAndroid Build Coastguard Worker size_t first = 0;
173*eb293b8fSAndroid Build Coastguard Worker size_t last = fde_count_;
174*eb293b8fSAndroid Build Coastguard Worker while (first < last) {
175*eb293b8fSAndroid Build Coastguard Worker size_t current = (first + last) / 2;
176*eb293b8fSAndroid Build Coastguard Worker const FdeInfo* info = GetFdeInfoFromIndex(current);
177*eb293b8fSAndroid Build Coastguard Worker if (info == nullptr) {
178*eb293b8fSAndroid Build Coastguard Worker return false;
179*eb293b8fSAndroid Build Coastguard Worker }
180*eb293b8fSAndroid Build Coastguard Worker if (pc == info->pc) {
181*eb293b8fSAndroid Build Coastguard Worker *fde_offset = info->offset;
182*eb293b8fSAndroid Build Coastguard Worker return true;
183*eb293b8fSAndroid Build Coastguard Worker }
184*eb293b8fSAndroid Build Coastguard Worker if (pc < info->pc) {
185*eb293b8fSAndroid Build Coastguard Worker last = current;
186*eb293b8fSAndroid Build Coastguard Worker } else {
187*eb293b8fSAndroid Build Coastguard Worker first = current + 1;
188*eb293b8fSAndroid Build Coastguard Worker }
189*eb293b8fSAndroid Build Coastguard Worker }
190*eb293b8fSAndroid Build Coastguard Worker if (last != 0) {
191*eb293b8fSAndroid Build Coastguard Worker const FdeInfo* info = GetFdeInfoFromIndex(last - 1);
192*eb293b8fSAndroid Build Coastguard Worker if (info == nullptr) {
193*eb293b8fSAndroid Build Coastguard Worker return false;
194*eb293b8fSAndroid Build Coastguard Worker }
195*eb293b8fSAndroid Build Coastguard Worker *fde_offset = info->offset;
196*eb293b8fSAndroid Build Coastguard Worker return true;
197*eb293b8fSAndroid Build Coastguard Worker }
198*eb293b8fSAndroid Build Coastguard Worker return false;
199*eb293b8fSAndroid Build Coastguard Worker }
200*eb293b8fSAndroid Build Coastguard Worker
201*eb293b8fSAndroid Build Coastguard Worker template <typename AddressType>
GetFdes(std::vector<const DwarfFde * > * fdes)202*eb293b8fSAndroid Build Coastguard Worker void DwarfEhFrameWithHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
203*eb293b8fSAndroid Build Coastguard Worker for (size_t i = 0; i < fde_count_; i++) {
204*eb293b8fSAndroid Build Coastguard Worker const FdeInfo* info = GetFdeInfoFromIndex(i);
205*eb293b8fSAndroid Build Coastguard Worker if (info == nullptr) {
206*eb293b8fSAndroid Build Coastguard Worker break;
207*eb293b8fSAndroid Build Coastguard Worker }
208*eb293b8fSAndroid Build Coastguard Worker const DwarfFde* fde = this->GetFdeFromOffset(info->offset);
209*eb293b8fSAndroid Build Coastguard Worker if (fde == nullptr) {
210*eb293b8fSAndroid Build Coastguard Worker break;
211*eb293b8fSAndroid Build Coastguard Worker }
212*eb293b8fSAndroid Build Coastguard Worker
213*eb293b8fSAndroid Build Coastguard Worker // There is a possibility that this entry points to a zero length FDE
214*eb293b8fSAndroid Build Coastguard Worker // due to a bug. If this happens, try and find the non-zero length FDE
215*eb293b8fSAndroid Build Coastguard Worker // from eh_frame directly. See b/142483624.
216*eb293b8fSAndroid Build Coastguard Worker if (fde->pc_start == fde->pc_end) {
217*eb293b8fSAndroid Build Coastguard Worker const DwarfFde* fde_real = DwarfSectionImpl<AddressType>::GetFdeFromPc(fde->pc_start);
218*eb293b8fSAndroid Build Coastguard Worker if (fde_real != nullptr) {
219*eb293b8fSAndroid Build Coastguard Worker fde = fde_real;
220*eb293b8fSAndroid Build Coastguard Worker }
221*eb293b8fSAndroid Build Coastguard Worker }
222*eb293b8fSAndroid Build Coastguard Worker fdes->push_back(fde);
223*eb293b8fSAndroid Build Coastguard Worker }
224*eb293b8fSAndroid Build Coastguard Worker }
225*eb293b8fSAndroid Build Coastguard Worker
226*eb293b8fSAndroid Build Coastguard Worker // Explicitly instantiate DwarfEhFrameWithHdr
227*eb293b8fSAndroid Build Coastguard Worker template class DwarfEhFrameWithHdr<uint32_t>;
228*eb293b8fSAndroid Build Coastguard Worker template class DwarfEhFrameWithHdr<uint64_t>;
229*eb293b8fSAndroid Build Coastguard Worker
230*eb293b8fSAndroid Build Coastguard Worker } // namespace unwindstack
231