xref: /aosp_15_r20/system/unwinding/libunwindstack/DwarfEhFrameWithHdr.cpp (revision eb293b8f56ee8303637c5595cfcdeef8039e85c6)
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